diff --git a/.eslintignore b/.eslintignore index 67cfff5b09..1b7d6301c4 100644 --- a/.eslintignore +++ b/.eslintignore @@ -14,3 +14,7 @@ site/.vitepress/cache/**/* **/test-results/* **/playwright-report/* pnpm-lock.yaml + +# codegen: committed spec snapshots (generated .ts files instead carry a +# file-level eslint-disable banner so lint-staged can pass them explicitly) +packages/api-codegen/specs/** diff --git a/nx.json b/nx.json index c53e11e87f..5f6ee5c358 100644 --- a/nx.json +++ b/nx.json @@ -11,8 +11,8 @@ }, "generate": { "dependsOn": ["^build"], - "outputs": ["{projectRoot}/src/plugins"], - "cache": true + "outputs": ["{projectRoot}/src/plugins", "{projectRoot}/src/generated"], + "cache": false }, "prepare": { "dependsOn": ["^build"], diff --git a/packages/api-codegen/README.md b/packages/api-codegen/README.md new file mode 100644 index 0000000000..eda0639238 --- /dev/null +++ b/packages/api-codegen/README.md @@ -0,0 +1,42 @@ +# @alchemy/api-codegen + +Internal (unpublished) codegen tool that generates SDK type internals from the +docs repo's bundled OpenAPI/OpenRPC specs. Design doc: `data-sdk-codegen-plan.md` +(alchemy-cli repo, alongside the data SDK scope plan). + +## Two-stage pipeline + +``` +alchemyplatform/docs (hand-authored YAML) + │ pnpm snapshot ← network/local-checkout stage, run rarely + ▼ +specs/*.json + specs.lock.json ← committed snapshots, pinned by docs SHA + sha256 + │ pnpm generate ← offline + deterministic, run on every change + ▼ +packages//src/generated/ ← committed TypeScript (prettier-formatted) +``` + +- **`pnpm --filter @alchemy/api-codegen snapshot`** — bundles specs from a local + docs checkout (`--docs `, `ALCHEMY_DOCS_DIR`, or `../docs` relative to the + repo root) using the docs repo's own tooling (redocly for OpenAPI, its + `generate:rpc` script for OpenRPC), copies the bundled JSON into `specs/`, and + writes `specs.lock.json` (docs commit SHA, branch, sha256 per file). The docs + working tree must be clean (`--allow-dirty` to override). +- **`pnpm generate`** (root, or `pnpm --filter @alchemy/data-apis generate`) — + reads only the committed snapshots, verifies checksums against the lockfile, + and emits TypeScript into the target package. Never touches the network. + +## Updating specs + +1. Pull/checkout the desired commit in your local docs clone. +2. `pnpm --filter @alchemy/api-codegen snapshot` +3. `pnpm generate` +4. Review the `specs/` + `src/generated/` diff and commit. + +## Targets + +Each consuming package declares a `codegen.manifest.ts` at its package root +(operationIds / RPC methods → export names, path normalization rules) and a +`generate` script invoking `src/cli.ts --target `. Targets are registered +in `src/targets/`. The generator hard-errors if a manifest references a spec +operation that no longer exists in the snapshot — that's the drift alarm. diff --git a/packages/api-codegen/package.json b/packages/api-codegen/package.json new file mode 100644 index 0000000000..8d3879e679 --- /dev/null +++ b/packages/api-codegen/package.json @@ -0,0 +1,25 @@ +{ + "name": "@alchemy/api-codegen", + "version": "0.0.0", + "description": "Internal codegen tool: generates SDK type internals from the docs repo's bundled OpenAPI/OpenRPC specs", + "author": "Alchemy", + "license": "MIT", + "private": true, + "type": "module", + "main": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": "./src/index.ts" + }, + "scripts": { + "snapshot": "tsx src/cli.ts snapshot", + "test": "vitest", + "test:run": "vitest run" + }, + "devDependencies": { + "json-schema-to-typescript": "15.0.4", + "openapi-typescript": "7.13.0", + "prettier": "3.3.3", + "typescript-template": "workspace:*" + } +} diff --git a/packages/api-codegen/specs/nft.json b/packages/api-codegen/specs/nft.json new file mode 100644 index 0000000000..456762762a --- /dev/null +++ b/packages/api-codegen/specs/nft.json @@ -0,0 +1,10336 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "🎨 NFT API", + "version": "1.0" + }, + "servers": [ + { + "url": "https://{network}.g.alchemy.com/nft", + "variables": { + "network": { + "default": "eth-mainnet", + "enum": [ + "eth-mainnet", + "eth-sepolia", + "abstract-mainnet", + "abstract-testnet", + "anime-mainnet", + "anime-sepolia", + "apechain-mainnet", + "apechain-curtis", + "arb-mainnet", + "arb-sepolia", + "avax-mainnet", + "avax-fuji", + "base-mainnet", + "base-sepolia", + "berachain-mainnet", + "blast-mainnet", + "blast-sepolia", + "bnb-mainnet", + "celo-mainnet", + "celo-sepolia", + "gnosis-mainnet", + "gnosis-chiado", + "lens-mainnet", + "lens-sepolia", + "linea-mainnet", + "linea-sepolia", + "polygon-mainnet", + "polygon-amoy", + "monad-mainnet", + "monad-testnet", + "mythos-mainnet", + "opt-mainnet", + "opt-sepolia", + "robinhood-testnet", + "ronin-mainnet", + "ronin-saigon", + "rootstock-mainnet", + "rootstock-testnet", + "scroll-mainnet", + "scroll-sepolia", + "settlus-mainnet", + "settlus-septestnet", + "shape-mainnet", + "shape-sepolia", + "soneium-mainnet", + "soneium-minato", + "starknet-mainnet", + "starknet-sepolia", + "story-mainnet", + "story-aeneid", + "unichain-mainnet", + "unichain-sepolia", + "worldchain-mainnet", + "worldchain-sepolia", + "zetachain-mainnet", + "zetachain-testnet", + "zksync-mainnet", + "zksync-sepolia", + "zora-mainnet", + "zora-sepolia" + ] + } + } + } + ], + "paths": { + "/v3/{apiKey}/getNFTsForOwner": { + "get": { + "summary": "NFTs By Owner", + "description": "getNFTsForOwner - Retrieves all NFTs currently owned by a specified address. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains).", + "tags": [ + "NFT Ownership Endpoints" + ], + "parameters": [ + { + "name": "owner", + "description": "String - Address for NFT owner (can be in ENS format for Eth Mainnet).", + "schema": { + "type": "string", + "default": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + }, + "in": "query", + "required": true + }, + { + "name": "contractAddresses[]", + "description": "Array of contract addresses to filter the responses with. Max limit 45 contracts.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + }, + "in": "query" + }, + { + "name": "withMetadata", + "description": "Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "schema": { + "type": "boolean", + "default": true + }, + "in": "query" + }, + { + "name": "orderBy", + "description": "Enum - ordering scheme to use for ordering NFTs in the response. If unspecified, NFTs will be ordered by contract address and token ID.\n - transferTime: NFTs will be ordered by the time they were transferred into the wallet, with newest NFTs first. Note: This ordering is supported on Ethereum Mainnet, Optimism Mainnet, Polygon Mainnet, Base Mainnet, Arbitrum One, Polygon Amoy, Base Sepolia, Arbitrum Sepolia, Ethereum Sepolia, and Optimism Sepolia.", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "transferTime" + ] + }, + "required": false + }, + { + "name": "excludeFilters[]", + "description": "Array of filters (as ENUMS) that will be applied to the query. NFTs that match one or more of these filters will be excluded from the response. May not be used in conjunction with includeFilters[]. Filter Options:\n - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**.\n - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only.\n - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts)", + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "in": "query" + }, + { + "name": "includeFilters[]", + "description": "Array of filters (as ENUMS) that will be applied to the query. Only NFTs that match one or more of these filters will be included in the response. May not be used in conjunction with excludeFilters[]. Filter Options:\n - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**.\n - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only.\n - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts)", + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "in": "query" + }, + { + "name": "spamConfidenceLevel", + "description": "Enum - the confidence level at which to filter spam at.\n\nConfidence Levels:\n - VERY_HIGH\n - HIGH\n - MEDIUM\n - LOW\n\nThe confidence level set means that any spam that is at that confidence level or higher will be filtered out. For example, if the confidence level is HIGH, contracts that we have HIGH or VERY_HIGH confidence in being spam will be filtered out from the response. \nDefaults to VERY_HIGH for Ethereum Mainnet and MEDIUM for Matic Mainnet.\n\n**Please note that this filter is only available on paid tiers. Upgrade your account [here](https://dashboard.alchemy.com/settings/billing/).**", + "schema": { + "type": "string", + "enum": [ + "VERY_HIGH", + "HIGH", + "MEDIUM", + "LOW" + ] + }, + "in": "query", + "required": false + }, + { + "name": "tokenUriTimeoutInMs", + "description": "No set timeout by default - When metadata is requested, this parameter is the timeout (in milliseconds) for the website hosting the metadata to respond. If you want to _only_ access the cache and not live fetch any metadata for cache misses then set this value to 0.", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "pageKey", + "description": "String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results.", + "schema": { + "type": "string" + }, + "in": "query" + }, + { + "name": "pageSize", + "description": "Number of NFTs to be returned per page. Defaults to 100. Max is 100.", + "schema": { + "type": "integer", + "default": 100 + }, + "in": "query" + } + ], + "responses": { + "200": { + "description": "Returns the list of all NFTs owned by the given address and satisfying the given input parameters.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "ownedNfts": { + "type": "array", + "description": "Array of the NFT objects corresponding to the NFTs owned by the owner", + "items": { + "type": "object", + "description": "The object that represents an NFT and has all data corresponding to that NFT", + "properties": { + "contract": { + "type": "object", + "description": "The contract object that has details of a contract", + "properties": { + "address": { + "description": "Address of the held contract", + "type": "string" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + }, + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "spamClassifications": { + "description": "List of reasons why a contract was classified as spam. **Only available on paid tiers.**", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenType": { + "type": "string" + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Brief human-readable description" + }, + "image": { + "type": "object", + "description": "Details of the image corresponding to this contract", + "properties": { + "cachedUrl": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "thumbnailUrl": { + "type": "string", + "description": "The Url that has the thumbnail version of the NFT" + }, + "pngUrl": { + "type": "string", + "description": "The Url that has the NFT image in png" + }, + "contentType": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "size": { + "type": "integer", + "description": "The size of the media asset in bytes." + }, + "originalUrl": { + "type": "string", + "description": "The original Url of the image coming straight from the smart contract" + } + } + }, + "raw": { + "type": "object", + "description": "Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract", + "properties": { + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "metadata": { + "type": "object", + "description": "Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually.", + "properties": { + "image": { + "type": "string", + "description": "String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces." + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms)" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trait_type": { + "type": "string" + } + } + }, + "description": "Object - Traits/attributes/characteristics for each NFT asset." + } + } + }, + "error": { + "type": "string", + "description": "String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT." + } + } + }, + "collection": { + "type": "object", + "description": "The collection object that has details of a collection", + "properties": { + "name": { + "type": "string", + "description": "String - Collection name" + }, + "slug": { + "type": "string", + "description": "String - OpenSea collection slug" + }, + "externalUrl": { + "type": "string", + "description": "String - URL for the external site of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "String - Banner image URL for the collection" + } + } + }, + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "timeLastUpdated": { + "type": "string", + "description": "String - ISO timestamp of the last cache refresh for the information returned in the metadata field." + }, + "acquiredAt": { + "type": "object", + "description": "Only present if the request specified `orderBy=transferTime`.", + "properties": { + "blockTimestamp": { + "type": "string", + "description": "Block timestamp of the block where the NFT was most recently acquired." + }, + "blockNumber": { + "type": "string", + "description": "Block number of the block where the NFT was most recently acquired." + } + } + }, + "animation": { + "type": "object", + "properties": { + "cachedUrl": { + "type": "string" + }, + "contentType": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "orginalUrl": { + "type": "string" + } + } + }, + "mint": { + "type": "object", + "properties": { + "mintAddress": { + "type": "string", + "description": "Address that minted the NFT" + }, + "blockNumber": { + "type": "integer", + "description": "Block number when the NFT was minted" + }, + "timestamp": { + "type": "string", + "description": "Timestamp when the NFT was minted" + }, + "transactionHash": { + "type": "string", + "description": "Transaction hash of the mint transaction" + } + } + }, + "owners": { + "type": "array", + "description": "List of all addresses that own the given NFT.", + "items": { + "type": "string" + } + } + } + } + }, + "totalCount": { + "type": "integer", + "description": "Integer - Total number of NFTs (distinct `tokenIds`) owned by the given address." + }, + "pageKey": { + "type": "string" + }, + "validAt": { + "type": "object", + "description": "Block Information of the block as of which the corresponding data is valid", + "properties": { + "blockNumber": { + "type": "integer", + "description": "The block number above information is valid as of" + }, + "blockHash": { + "type": "string", + "description": "The block hash above information is valid as of" + }, + "blockTimestamp": { + "type": "string", + "description": "The block timestamp above information is valid as of" + } + } + } + } + }, + "examples": { + "byDefault": { + "summary": "Response (By Default)", + "value": { + "ownedNfts": [ + { + "contract": { + "address": "0x0bEed7099AF7514cCEDF642CfEA435731176Fb02", + "name": "DuskBreakers", + "symbol": "DUSK", + "totalSupply": "10000", + "tokenType": "ERC721", + "contractDeployer": "0x9c78DDec1F16685ee6E58637a640514A1eD87BC4", + "deployedBlockNumber": 13736379, + "openSeaMetadata": { + "floorPrice": 0.0582, + "collectionName": "DuskBreakers", + "safelistRequestStatus": "verified", + "imageUrl": "https://i.seadn.io/gae/LGbFRVdClz6-HDd-7WZKONJ5Ody0sBXTvFOQL71BYo3j2iU2wWCX_zlk-Zs0KEhq1qgXViF-6aG_0WS2MdIVNJx2GRSIIYTiciuf-A?w=500&auto=format", + "description": "Being a DuskBreaker means joining a select squad of 10,000 recruits who spend their days exploring a mysterious alien spaceship filled with friends, foes, and otherworldly technology. You will be part of a community that directly influences the development of upcoming interactive media and gaming experiences within the DuskBreakers universe. Each of you will play an important role in building out this world. You break it, you take it! \r\n\r\nVisit [DuskBreakers](https://duskbreakers.gg) to learn more.", + "externalUrl": "http://duskbreakers.gg", + "twitterUsername": "duskbreakers", + "discordUrl": "https://discord.gg/duskbreakers", + "lastIngestedAt": "2023-04-19T17:25:59.000Z" + }, + "isSpam": null, + "spamClassifications": [] + }, + "tokenId": "28", + "tokenType": "ERC721", + "name": "DuskBreaker #28", + "description": "Breakers have the honor of serving humanity through their work on The Dusk. They are part of a select squad of 10,000 recruits who spend their days exploring a mysterious alien spaceship filled with friends, foes, and otherworldly technology.", + "image": { + "cachedUrl": "https://nft-cdn.alchemy.com/eth-mainnet/1f9e8be3feb42b5b66452537a4032668", + "thumbnailUrl": "https://res.cloudinary.com/alchemyapi/image/upload/thumbnailv2/eth-mainnet/1f9e8be3feb42b5b66452537a4032668", + "pngUrl": "https://res.cloudinary.com/alchemyapi/image/upload/convert-png/eth-mainnet/1f9e8be3feb42b5b66452537a4032668", + "contentType": "image/png", + "size": 1474037, + "originalUrl": "https://duskbreakers.gg/breaker_images/28.png" + }, + "raw": { + "tokenUri": "https://api.duskbreakers.gg/metadata/duskbreakers/28", + "metadata": { + "name": "DuskBreaker #28", + "description": "Breakers have the honor of serving humanity through their work on The Dusk. They are part of a select squad of 10,000 recruits who spend their days exploring a mysterious alien spaceship filled with friends, foes, and otherworldly technology.", + "image": "https://duskbreakers.gg/breaker_images/28.png", + "external_url": "https://duskbreakers.gg/", + "attributes": [ + { + "value": "Locust Rider Armor (Red)", + "trait_type": "Clothes" + }, + { + "value": "Base Drone (Blue)", + "trait_type": "Drone" + }, + { + "value": "Thin", + "trait_type": "Eyebrows" + }, + { + "value": "Button", + "trait_type": "Nose" + }, + { + "value": "Mohawk (Black)", + "trait_type": "Hair" + }, + { + "value": "Almond 2 (Red)", + "trait_type": "Eyes" + }, + { + "value": "Big Smile (Purple)", + "trait_type": "Mouth" + }, + { + "value": "Light Brown", + "trait_type": "Skin Tone" + }, + { + "value": "Yellow", + "trait_type": "Background" + }, + { + "value": "Facepaint (Stripe)", + "trait_type": "Face Augments" + } + ] + }, + "error": null + }, + "tokenUri": "https://api.duskbreakers.gg/metadata/duskbreakers/28", + "timeLastUpdated": "2023-04-19T21:25:39.563Z", + "balance": "1" + }, + { + "contract": { + "address": "0x0bEed7099AF7514cCEDF642CfEA435731176Fb02", + "name": "DuskBreakers", + "symbol": "DUSK", + "totalSupply": "10000", + "tokenType": "ERC721", + "contractDeployer": "0x9c78DDec1F16685ee6E58637a640514A1eD87BC4", + "deployedBlockNumber": 13736379, + "openSeaMetadata": { + "floorPrice": 0.0582, + "collectionName": "DuskBreakers", + "safelistRequestStatus": "verified", + "imageUrl": "https://i.seadn.io/gae/LGbFRVdClz6-HDd-7WZKONJ5Ody0sBXTvFOQL71BYo3j2iU2wWCX_zlk-Zs0KEhq1qgXViF-6aG_0WS2MdIVNJx2GRSIIYTiciuf-A?w=500&auto=format", + "description": "Being a DuskBreaker means joining a select squad of 10,000 recruits who spend their days exploring a mysterious alien spaceship filled with friends, foes, and otherworldly technology. You will be part of a community that directly influences the development of upcoming interactive media and gaming experiences within the DuskBreakers universe. Each of you will play an important role in building out this world. You break it, you take it! \r\n\r\nVisit [DuskBreakers](https://duskbreakers.gg) to learn more.", + "externalUrl": "http://duskbreakers.gg", + "twitterUsername": "duskbreakers", + "discordUrl": "https://discord.gg/duskbreakers", + "lastIngestedAt": "2023-04-19T17:25:59.000Z" + }, + "isSpam": null, + "spamClassifications": [] + }, + "tokenId": "29", + "tokenType": "ERC721", + "name": "DuskBreaker #29", + "description": "Breakers have the honor of serving humanity through their work on The Dusk. They are part of a select squad of 10,000 recruits who spend their days exploring a mysterious alien spaceship filled with friends, foes, and otherworldly technology.", + "image": { + "cachedUrl": "https://nft-cdn.alchemy.com/eth-mainnet/4eb0b7f434746250ff3c8200d10a2226", + "thumbnailUrl": "https://res.cloudinary.com/alchemyapi/image/upload/thumbnailv2/eth-mainnet/4eb0b7f434746250ff3c8200d10a2226", + "pngUrl": "https://res.cloudinary.com/alchemyapi/image/upload/convert-png/eth-mainnet/4eb0b7f434746250ff3c8200d10a2226", + "contentType": "image/png", + "size": 1480183, + "originalUrl": "https://duskbreakers.gg/breaker_images/29.png" + }, + "raw": { + "tokenUri": "https://api.duskbreakers.gg/metadata/duskbreakers/29", + "metadata": { + "name": "DuskBreaker #29", + "description": "Breakers have the honor of serving humanity through their work on The Dusk. They are part of a select squad of 10,000 recruits who spend their days exploring a mysterious alien spaceship filled with friends, foes, and otherworldly technology.", + "image": "https://duskbreakers.gg/breaker_images/29.png", + "external_url": "https://duskbreakers.gg/", + "attributes": [ + { + "value": "Standard Issue Armor 1 (Orange)", + "trait_type": "Clothes" + }, + { + "value": "Dark Metal", + "trait_type": "SmartSkin" + }, + { + "value": "Base Drone (Purple)", + "trait_type": "Drone" + }, + { + "value": "Thin", + "trait_type": "Eyebrows" + }, + { + "value": "Broad", + "trait_type": "Nose" + }, + { + "value": "Slick Back (Red)", + "trait_type": "Hair" + }, + { + "value": "Sharp (Blue)", + "trait_type": "Eyes" + }, + { + "value": "Smirk (Neutral)", + "trait_type": "Mouth" + }, + { + "value": "Tan", + "trait_type": "Skin Tone" + }, + { + "value": "Purple", + "trait_type": "Background" + } + ] + }, + "error": null + }, + "tokenUri": "https://api.duskbreakers.gg/metadata/duskbreakers/29", + "timeLastUpdated": "2023-04-19T21:25:39.704Z", + "balance": "1" + }, + { + "contract": { + "address": "0x209cE666978779756Ae1E747608cD93e4dFf45fD", + "name": "Knight of Chains Genesis", + "symbol": "Knight of Chains Genesis", + "totalSupply": null, + "tokenType": "ERC1155", + "contractDeployer": "0xA92520aFF50c5A1a4d25FCF90c972AA49EbE5299", + "deployedBlockNumber": 14847327, + "openSeaMetadata": { + "floorPrice": null, + "collectionName": "Knight of Chains Genesis.", + "safelistRequestStatus": "not_requested", + "imageUrl": "https://i.seadn.io/gae/eRhkkVikIOW_-lDc1moMrZlTcd5DPygPRmTJ69Anb-CfG_RMAxIsichM5kDvfdnXc6gfnKuGZOFCbP_58pUvz57TyUeNbFMKGydHoac?w=500&auto=format", + "description": "[The KnightsOfChain] (https://knightsofchain.link) is an exclusive community that can only be entered by owning a Knight.\n\nVisit [Website](https://knightsofchain.link) and get your benefits.\n\n(Genesis Knights #1-#31 were pre-minted by the team, and are held by high ranking community members. OG Knights #32-#231 have special benefits.)", + "externalUrl": "https://knightsofchain.link", + "twitterUsername": null, + "discordUrl": null, + "lastIngestedAt": "2023-03-20T03:52:07.000Z" + }, + "isSpam": null, + "spamClassifications": [] + }, + "tokenId": "97", + "tokenType": "ERC1155", + "name": null, + "description": null, + "image": { + "cachedUrl": null, + "thumbnailUrl": null, + "pngUrl": null, + "contentType": null, + "size": null, + "originalUrl": null + }, + "raw": { + "tokenUri": "https://knightsofchain.link/ipfs/97", + "metadata": {}, + "error": null + }, + "tokenUri": "https://knightsofchain.link/ipfs/97", + "timeLastUpdated": "2023-04-20T15:44:29.965Z", + "balance": "1" + } + ], + "totalCount": 3, + "validAt": { + "blockNumber": 17091500, + "blockHash": "0x2a34a65c4e0cd7fdf187d6a497214ad2bee255d2d3501868a6b8c09b4d1261bd", + "blockTimestamp": "2023-04-21T01:25:59Z" + }, + "pageKey": null + } + }, + "withoutMetadata": { + "summary": "Response (withMetadata = false)", + "value": { + "ownedNfts": [ + { + "contractAddress": "0x0bEed7099AF7514cCEDF642CfEA435731176Fb02", + "tokenId": "28", + "balance": "1" + }, + { + "contractAddress": "0x0bEed7099AF7514cCEDF642CfEA435731176Fb02", + "tokenId": "29", + "balance": "1" + } + ], + "totalCount": 2, + "validAt": { + "blockNumber": 17091500, + "blockHash": "0x2a34a65c4e0cd7fdf187d6a497214ad2bee255d2d3501868a6b8c09b4d1261bd", + "blockTimestamp": "2023-04-21T01:25:59Z" + }, + "pageKey": null + } + }, + "withContractFiltering": { + "summary": "Response (with contract filtering)", + "value": { + "ownedNfts": [ + { + "contractAddress": "0x0bEed7099AF7514cCEDF642CfEA435731176Fb02", + "tokenId": "28", + "balance": "1" + }, + { + "contractAddress": "0x0bEed7099AF7514cCEDF642CfEA435731176Fb02", + "tokenId": "29", + "balance": "1" + } + ], + "totalCount": 2, + "validAt": { + "blockNumber": 17091500, + "blockHash": "0x2a34a65c4e0cd7fdf187d6a497214ad2bee255d2d3501868a6b8c09b4d1261bd", + "blockTimestamp": "2023-04-21T01:25:59Z" + }, + "pageKey": null + } + }, + "withPagination": { + "summary": "Response (with pagination)", + "value": { + "ownedNfts": [ + { + "contractAddress": "0x0bEed7099AF7514cCEDF642CfEA435731176Fb02", + "tokenId": "28", + "balance": "1" + }, + { + "contractAddress": "0x0bEed7099AF7514cCEDF642CfEA435731176Fb02", + "tokenId": "29", + "balance": "1" + } + ], + "totalCount": 2, + "validAt": { + "blockNumber": 17091500, + "blockHash": "0x2a34a65c4e0cd7fdf187d6a497214ad2bee255d2d3501868a6b8c09b4d1261bd", + "blockTimestamp": "2023-04-21T01:25:59Z" + }, + "pageKey": "88434286-7eaa-472d-8739-32a0497c2a18" + } + } + } + } + } + } + }, + "operationId": "getNFTsForOwner-v3" + } + }, + "/v3/{apiKey}/getNFTsForContract": { + "get": { + "summary": "NFTs By Contract", + "description": "getNFTsForContract - Retrieves all NFTs associated with a specific NFT contract. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains).", + "tags": [ + "NFT Metadata Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + }, + { + "name": "withMetadata", + "description": "Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "schema": { + "type": "boolean", + "default": true + }, + "in": "query" + }, + { + "name": "startToken", + "description": "String - A tokenID offset used for pagination. Can be a hex string, or a decimal. Users can specify the offset themselves to start from a custom offset, or to fetch multiple token ranges in parallel.", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "description": "Integer - Sets the total number of NFTs returned in the response. Defaults to 100.", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "tokenUriTimeoutInMs", + "description": "No set timeout by default - When metadata is requested, this parameter is the timeout (in milliseconds) for the website hosting the metadata to respond. If you want to _only_ access the cache and not live fetch any metadata for cache misses then set this value to 0.", + "in": "query", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Returns a list of NFTs associated with the specified contract address.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "nfts": { + "description": "List of objects that represent NFTs stored under the queried contract address.", + "type": "array", + "items": { + "type": "object", + "description": "The object that represents an NFT and has all data corresponding to that NFT", + "properties": { + "contract": { + "type": "object", + "description": "The contract object that has details of a contract", + "properties": { + "address": { + "description": "Address of the held contract", + "type": "string" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + }, + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "spamClassifications": { + "description": "List of reasons why a contract was classified as spam. **Only available on paid tiers.**", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenType": { + "type": "string" + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Brief human-readable description" + }, + "image": { + "type": "object", + "description": "Details of the image corresponding to this contract", + "properties": { + "cachedUrl": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "thumbnailUrl": { + "type": "string", + "description": "The Url that has the thumbnail version of the NFT" + }, + "pngUrl": { + "type": "string", + "description": "The Url that has the NFT image in png" + }, + "contentType": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "size": { + "type": "integer", + "description": "The size of the media asset in bytes." + }, + "originalUrl": { + "type": "string", + "description": "The original Url of the image coming straight from the smart contract" + } + } + }, + "raw": { + "type": "object", + "description": "Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract", + "properties": { + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "metadata": { + "type": "object", + "description": "Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually.", + "properties": { + "image": { + "type": "string", + "description": "String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces." + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms)" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trait_type": { + "type": "string" + } + } + }, + "description": "Object - Traits/attributes/characteristics for each NFT asset." + } + } + }, + "error": { + "type": "string", + "description": "String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT." + } + } + }, + "collection": { + "type": "object", + "description": "The collection object that has details of a collection", + "properties": { + "name": { + "type": "string", + "description": "String - Collection name" + }, + "slug": { + "type": "string", + "description": "String - OpenSea collection slug" + }, + "externalUrl": { + "type": "string", + "description": "String - URL for the external site of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "String - Banner image URL for the collection" + } + } + }, + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "timeLastUpdated": { + "type": "string", + "description": "String - ISO timestamp of the last cache refresh for the information returned in the metadata field." + }, + "acquiredAt": { + "type": "object", + "description": "Only present if the request specified `orderBy=transferTime`.", + "properties": { + "blockTimestamp": { + "type": "string", + "description": "Block timestamp of the block where the NFT was most recently acquired." + }, + "blockNumber": { + "type": "string", + "description": "Block number of the block where the NFT was most recently acquired." + } + } + }, + "animation": { + "type": "object", + "properties": { + "cachedUrl": { + "type": "string" + }, + "contentType": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "orginalUrl": { + "type": "string" + } + } + }, + "mint": { + "type": "object", + "properties": { + "mintAddress": { + "type": "string", + "description": "Address that minted the NFT" + }, + "blockNumber": { + "type": "integer", + "description": "Block number when the NFT was minted" + }, + "timestamp": { + "type": "string", + "description": "Timestamp when the NFT was minted" + }, + "transactionHash": { + "type": "string", + "description": "Transaction hash of the mint transaction" + } + } + }, + "owners": { + "type": "array", + "description": "List of all addresses that own the given NFT.", + "items": { + "type": "string" + } + } + } + } + }, + "pageKey": { + "type": "string", + "description": "String - An offset used for pagination. Can be passed back as the \"startToken\" of a subsequent request to get the next page of results. Absent if there are no more results." + } + } + } + } + } + } + }, + "operationId": "getNFTsForContract-v3" + } + }, + "/v3/{apiKey}/getNFTsForCollection": { + "get": { + "summary": "NFTs By Collection", + "description": "getNFTsForCollection - Retrieves all NFTs associated with a specific NFT collection. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains).", + "tags": [ + "NFT Metadata Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "collectionSlug", + "description": "String - OpenSea slug for the NFT collection.", + "in": "query", + "schema": { + "type": "string", + "default": "boredapeyachtclub" + }, + "required": false + }, + { + "name": "withMetadata", + "description": "Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "schema": { + "type": "boolean", + "default": true + }, + "in": "query" + }, + { + "name": "startToken", + "description": "String - A tokenID offset used for pagination. Can be a hex string, or a decimal. Users can specify the offset themselves to start from a custom offset, or to fetch multiple token ranges in parallel.", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "description": "Integer - Sets the total number of NFTs returned in the response. Defaults to 100.", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "tokenUriTimeoutInMs", + "description": "No set timeout by default - When metadata is requested, this parameter is the timeout (in milliseconds) for the website hosting the metadata to respond. If you want to _only_ access the cache and not live fetch any metadata for cache misses then set this value to 0.", + "in": "query", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Returns a list of NFTs associated with the specified collection.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "nfts": { + "description": "List of objects that represent NFTs stored under the queried contract address or collection slug.", + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "object", + "properties": { + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenMetadata": { + "type": "object", + "properties": { + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + } + } + } + } + }, + "tokenUri": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + } + } + }, + "metadata": { + "type": "object", + "description": "Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually.", + "properties": { + "image": { + "type": "string", + "description": "String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces." + }, + "external_url": { + "type": "string", + "description": "String - The image URL that appears alongside the asset image on NFT platforms." + }, + "background_color": { + "type": "string", + "description": "String - Background color of the NFT item. Usually must be defined as a six-character hexadecimal." + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms)" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trait_type": { + "type": "string" + } + } + }, + "description": "Object - Traits/attributes/characteristics for each NFT asset." + }, + "media": { + "type": "array", + "items": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + }, + "thumbnail": { + "type": "string", + "description": "URL for a resized thumbnail of the NFT media asset." + }, + "format": { + "type": "string", + "description": "The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets." + }, + "bytes": { + "type": "integer", + "description": "The size of the media asset in bytes." + } + } + } + } + } + }, + "timeLastUpdated": { + "type": "string", + "description": "String - ISO timestamp of the last cache refresh for the information returned in the metadata field." + }, + "contractMetadata": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "opensea": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + } + } + } + } + } + }, + "nextToken": { + "type": "string", + "description": "String - An offset used for pagination. Can be passed back as the \"startToken\" of a subsequent request to get the next page of results. Absent if there are no more results." + } + } + } + } + } + } + }, + "operationId": "getNFTsForCollection-v3" + } + }, + "/v3/{apiKey}/getNFTMetadata": { + "get": { + "summary": "NFT Metadata By Token ID", + "description": "getNFTMetadata - Retrieves the metadata associated with a specific NFT. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains).", + "tags": [ + "NFT Metadata Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + }, + { + "name": "tokenId", + "description": "String - The ID of the token. Can be in hex or decimal format.", + "in": "query", + "schema": { + "type": "string", + "default": "44" + }, + "required": true + }, + { + "name": "tokenType", + "description": "String - 'ERC721' or 'ERC1155'; specifies type of token to query for. API requests will perform faster if this is specified.", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "tokenUriTimeoutInMs", + "description": "No set timeout by default - When metadata is requested, this parameter is the timeout (in milliseconds) for the website hosting the metadata to respond. If you want to _only_ access the cache and not live fetch any metadata for cache misses then set this value to 0.", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "refreshCache", + "description": "Defaults to false for faster response times. If true will refresh metadata for given token. If false will check the cache and use it or refresh if cache doesn't exist.", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Returns the metadata of the specified NFT.", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "The object that represents an NFT and has all data corresponding to that NFT", + "properties": { + "contract": { + "type": "object", + "description": "The contract object that has details of a contract", + "properties": { + "address": { + "description": "Address of the held contract", + "type": "string" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + }, + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "spamClassifications": { + "description": "List of reasons why a contract was classified as spam. **Only available on paid tiers.**", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenType": { + "type": "string" + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Brief human-readable description" + }, + "image": { + "type": "object", + "description": "Details of the image corresponding to this contract", + "properties": { + "cachedUrl": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "thumbnailUrl": { + "type": "string", + "description": "The Url that has the thumbnail version of the NFT" + }, + "pngUrl": { + "type": "string", + "description": "The Url that has the NFT image in png" + }, + "contentType": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "size": { + "type": "integer", + "description": "The size of the media asset in bytes." + }, + "originalUrl": { + "type": "string", + "description": "The original Url of the image coming straight from the smart contract" + } + } + }, + "raw": { + "type": "object", + "description": "Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract", + "properties": { + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "metadata": { + "type": "object", + "description": "Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually.", + "properties": { + "image": { + "type": "string", + "description": "String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces." + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms)" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trait_type": { + "type": "string" + } + } + }, + "description": "Object - Traits/attributes/characteristics for each NFT asset." + } + } + }, + "error": { + "type": "string", + "description": "String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT." + } + } + }, + "collection": { + "type": "object", + "description": "The collection object that has details of a collection", + "properties": { + "name": { + "type": "string", + "description": "String - Collection name" + }, + "slug": { + "type": "string", + "description": "String - OpenSea collection slug" + }, + "externalUrl": { + "type": "string", + "description": "String - URL for the external site of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "String - Banner image URL for the collection" + } + } + }, + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "timeLastUpdated": { + "type": "string", + "description": "String - ISO timestamp of the last cache refresh for the information returned in the metadata field." + }, + "acquiredAt": { + "type": "object", + "description": "Only present if the request specified `orderBy=transferTime`.", + "properties": { + "blockTimestamp": { + "type": "string", + "description": "Block timestamp of the block where the NFT was most recently acquired." + }, + "blockNumber": { + "type": "string", + "description": "Block number of the block where the NFT was most recently acquired." + } + } + }, + "animation": { + "type": "object", + "properties": { + "cachedUrl": { + "type": "string" + }, + "contentType": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "orginalUrl": { + "type": "string" + } + } + }, + "mint": { + "type": "object", + "properties": { + "mintAddress": { + "type": "string", + "description": "Address that minted the NFT" + }, + "blockNumber": { + "type": "integer", + "description": "Block number when the NFT was minted" + }, + "timestamp": { + "type": "string", + "description": "Timestamp when the NFT was minted" + }, + "transactionHash": { + "type": "string", + "description": "Transaction hash of the mint transaction" + } + } + }, + "owners": { + "type": "array", + "description": "List of all addresses that own the given NFT.", + "items": { + "type": "string" + } + } + } + } + } + } + } + }, + "operationId": "getNFTMetadata-v3" + } + }, + "/v3/{apiKey}/getNFTMetadataBatch": { + "post": { + "summary": "NFT Metadata By Token ID [Batch]", + "description": "getNFTMetadataBatch - Retrieves metadata for up to 100 specified NFT contracts in a single request. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains).", + "tags": [ + "NFT Metadata Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "tokens" + ], + "properties": { + "tokens": { + "type": "array", + "description": "List of token objects to batch request NFT metadata for. Maximum 100.", + "items": { + "type": "object", + "required": [ + "contractAddress", + "tokenId" + ], + "properties": { + "contractAddress": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenType": { + "type": "string" + } + } + } + }, + "tokenUriTimeoutInMs": { + "type": "integer" + }, + "refreshCache": { + "type": "boolean", + "default": false + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Returns an array of NFT metadata corresponding to the batch query.", + "content": { + "application/json": { + "schema": { + "type": "array", + "description": "Array of NFT objects corresponding to the query", + "items": { + "type": "object", + "description": "The object that represents an NFT and has all data corresponding to that NFT", + "properties": { + "contract": { + "type": "object", + "description": "The contract object that has details of a contract", + "properties": { + "address": { + "description": "Address of the held contract", + "type": "string" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + }, + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "spamClassifications": { + "description": "List of reasons why a contract was classified as spam. **Only available on paid tiers.**", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenType": { + "type": "string" + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Brief human-readable description" + }, + "image": { + "type": "object", + "description": "Details of the image corresponding to this contract", + "properties": { + "cachedUrl": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "thumbnailUrl": { + "type": "string", + "description": "The Url that has the thumbnail version of the NFT" + }, + "pngUrl": { + "type": "string", + "description": "The Url that has the NFT image in png" + }, + "contentType": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "size": { + "type": "integer", + "description": "The size of the media asset in bytes." + }, + "originalUrl": { + "type": "string", + "description": "The original Url of the image coming straight from the smart contract" + } + } + }, + "raw": { + "type": "object", + "description": "Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract", + "properties": { + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "metadata": { + "type": "object", + "description": "Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually.", + "properties": { + "image": { + "type": "string", + "description": "String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces." + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms)" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trait_type": { + "type": "string" + } + } + }, + "description": "Object - Traits/attributes/characteristics for each NFT asset." + } + } + }, + "error": { + "type": "string", + "description": "String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT." + } + } + }, + "collection": { + "type": "object", + "description": "The collection object that has details of a collection", + "properties": { + "name": { + "type": "string", + "description": "String - Collection name" + }, + "slug": { + "type": "string", + "description": "String - OpenSea collection slug" + }, + "externalUrl": { + "type": "string", + "description": "String - URL for the external site of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "String - Banner image URL for the collection" + } + } + }, + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "timeLastUpdated": { + "type": "string", + "description": "String - ISO timestamp of the last cache refresh for the information returned in the metadata field." + }, + "acquiredAt": { + "type": "object", + "description": "Only present if the request specified `orderBy=transferTime`.", + "properties": { + "blockTimestamp": { + "type": "string", + "description": "Block timestamp of the block where the NFT was most recently acquired." + }, + "blockNumber": { + "type": "string", + "description": "Block number of the block where the NFT was most recently acquired." + } + } + }, + "animation": { + "type": "object", + "properties": { + "cachedUrl": { + "type": "string" + }, + "contentType": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "orginalUrl": { + "type": "string" + } + } + }, + "mint": { + "type": "object", + "properties": { + "mintAddress": { + "type": "string", + "description": "Address that minted the NFT" + }, + "blockNumber": { + "type": "integer", + "description": "Block number when the NFT was minted" + }, + "timestamp": { + "type": "string", + "description": "Timestamp when the NFT was minted" + }, + "transactionHash": { + "type": "string", + "description": "Transaction hash of the mint transaction" + } + } + }, + "owners": { + "type": "array", + "description": "List of all addresses that own the given NFT.", + "items": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "operationId": "getNFTMetadataBatch-v3" + } + }, + "/v3/{apiKey}/getContractMetadata": { + "get": { + "summary": "Contract Metadata By Address", + "description": "getContractMetadata - Retrieves high-level collection or contract-level information for an NFT. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains).", + "tags": [ + "NFT Metadata Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "Returns the contract metadata for the specified address.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "String - Contract address for the queried NFT collection" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + } + } + } + } + } + } + }, + "operationId": "getContractMetadata-v3" + } + }, + "/v3/{apiKey}/getCollectionMetadata": { + "get": { + "summary": "Collection Metadata By Slug", + "description": "getCollectionMetadata - Retrieves high-level collection or contract-level information for an NFT collection. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains).", + "tags": [ + "NFT Metadata Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "collectionSlug", + "description": "String - OpenSea slug for the NFT collection.", + "in": "query", + "schema": { + "type": "string", + "default": "boredapeyachtclub" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "Returns the collection metadata for the specified slug.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "String - Name of the queried NFT Collection" + }, + "slug": { + "description": "The human-readable string used to identify the collection on OpenSea.", + "type": "string" + }, + "floorPrice": { + "type": "object", + "description": "Floor price data for the collection", + "properties": { + "marketplace": { + "description": "The marketplace the floor price is on", + "type": "string" + }, + "floorPrice": { + "description": "Floor price of the collection on the marketplace", + "type": "number" + }, + "priceCurrency": { + "description": "The currency of the floor price", + "type": "string" + } + } + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + } + } + } + } + } + } + }, + "operationId": "getCollectionMetadata-v3" + } + }, + "/v3/{apiKey}/invalidateContract": { + "get": { + "summary": "Invalidate Contract Cache", + "description": "Marks all cached tokens for the specified contract as stale, ensuring the next query fetches live data instead of cached data.\n\nPlease note that this endpoint is only available on **Ethereum**, **Polygon**, **Arbitrum**, **Optimism** & **Base** networks.\n", + "tags": [ + "NFT Metadata Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "Returns confirmation of cache invalidation along with the number of tokens invalidated.", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "True - if the queried contract is marked as spam.\nFalse - if the queried contract is considered valid.\n", + "properties": { + "success": { + "type": "string", + "description": "True if the contract was invalidated.\nFalse - if it wasn't.\n" + }, + "numTokensInvalidated": { + "type": "number", + "description": "The number of tokens that were invalidated as a result of running this query." + } + } + } + } + } + } + }, + "operationId": "invalidateContract-v3" + } + }, + "/v3/{apiKey}/getContractMetadataBatch": { + "post": { + "summary": "Contract Metadata By Address [Batch]", + "description": "getContractMetadataBatch - Retrieves metadata for a list of specified contract addresses in a single request.", + "tags": [ + "NFT Metadata Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "contractAddresses": { + "type": "array", + "description": "List of contract addresses to batch metadata requests for.", + "default": [ + "0xe785E82358879F061BC3dcAC6f0444462D4b5330", + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d" + ], + "items": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Returns an array of contract metadata corresponding to the batch query.", + "content": { + "application/json": { + "schema": { + "type": "array", + "description": "Array of contract metadata objects corresponding to the query.", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "String - Contract address for the queried NFT collection" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + } + } + } + } + } + } + } + }, + "operationId": "getContractMetadataBatch-v3" + } + }, + "/v3/{apiKey}/getOwnersForNFT": { + "get": { + "summary": "Owners By NFT", + "description": "getOwnersForNFT - Retrieves the owner(s) for a specific token. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains).", + "tags": [ + "NFT Ownership Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + }, + { + "name": "tokenId", + "description": "String - The ID of the token. Can be in hex or decimal format.", + "in": "query", + "schema": { + "type": "string", + "default": "44" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "Returns the owner(s) of the specified NFT.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "owners": { + "type": "array", + "description": "List of all addresses that own the given NFT.", + "items": { + "type": "string" + } + }, + "pageKey": { + "type": "string" + } + } + }, + "examples": { + "getOwnersForNFT_response": { + "value": { + "owners": [ + "0x9f4F78A6c4a5E6F8AFA81631b9120ae3C831b494" + ], + "pageKey": null + } + } + } + } + } + } + }, + "operationId": "getOwnersForNFT-v3" + } + }, + "/v3/{apiKey}/getOwnersForContract": { + "get": { + "summary": "Owners By Contract", + "description": "getOwnersForContract - Retrieves all owners associated with a specific NFT contract. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains).", + "tags": [ + "NFT Ownership Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0x495f947276749ce646f68ac8c248420045cb7b5e" + }, + "required": true + }, + { + "name": "withTokenBalances", + "description": "Boolean - If set to `true` the query will include the token balances per token id for each owner. `false` by default.", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "description": "String - used for contracts with >50,000 owners. `pageKey` field can be passed back as request parameter to get the next page of results.", + "name": "pageKey", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "responses": { + "200": { + "description": "Returns a list of all owners for the specified contract.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "owners": { + "description": "List of all addresses that own one of the NFTs from the queried contract address. The format is applicable when `withTokenBalances=true`.", + "type": "array", + "items": { + "type": "object", + "properties": { + "ownerAddress": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "tokenBalances": { + "type": "array", + "description": "a list of the token ids and balances for the owner of the collection", + "items": { + "type": "object", + "properties": { + "tokenId": { + "type": "string", + "description": "tokenId of the NFT in the collection that an owner has" + }, + "balance": { + "type": "integer", + "description": "the number of the specified token in the collection that the user owns" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "operationId": "getOwnersForContract-v3" + } + }, + "/v3/{apiKey}/getSpamContracts": { + "get": { + "summary": "Spam Contracts", + "description": "Returns a list of all spam contracts marked by Alchemy.\n\nPlease note that this API endpoint is only available to paid tier customers. Upgrade your account [here](https://dashboard.alchemy.com/account).\n\nSpam NFT functionality is available on Mainnet for the following chains: Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast. More to come soon!\n", + "tags": [ + "NFT Spam Endpoints" + ], + "servers": [ + { + "url": "https://{network}.g.alchemy.com/nft", + "variables": { + "network": { + "enum": [ + "eth-mainnet", + "polygon-mainnet" + ], + "default": "eth-mainnet" + } + } + } + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "Returns a list of all spam contracts marked by Alchemy.", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "Object that contains a list of contract addresses.", + "properties": { + "contractAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "description": "A list of contract addresses earmarked as spam by Alchemy." + } + } + } + } + } + } + }, + "operationId": "getSpamContracts-v3" + } + }, + "/v3/{apiKey}/isSpamContract": { + "get": { + "summary": "Is Spam Contract", + "description": "Determines whether a specific contract is marked as spam by Alchemy.\n\nPlease note that this API endpoint is only available to paid tier customers. Upgrade your account [here](https://dashboard.alchemy.com/account).\n\nSpam NFT functionality is available on Mainnet for the following chains: Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast. More to come soon!\n", + "tags": [ + "NFT Spam Endpoints" + ], + "servers": [ + { + "url": "https://{network}.g.alchemy.com/nft", + "variables": { + "network": { + "enum": [ + "eth-mainnet", + "polygon-mainnet" + ], + "default": "eth-mainnet" + } + } + } + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0x495f947276749ce646f68ac8c248420045cb7b5e" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "Returns whether the specified contract is marked as spam.", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "This object contains a boolean value indicating the spam status of the contract.", + "properties": { + "isSpamContract": { + "type": "boolean", + "description": "True - if the queried contract is marked as spam.\nFalse - if the queried contract is considered valid.\n" + } + } + } + } + } + } + }, + "operationId": "isSpamContract-v3" + } + }, + "/v3/{apiKey}/isAirdropNFT": { + "get": { + "summary": "Is Airdrop NFT", + "description": "Determines whether a specific token is marked as an airdrop. Airdrops are defined as NFTs minted to a user address in a transaction sent by a different address.\n\nPlease note that this endpoint is only available on Ethereum (mainnet only) & Polygon (mainnet, amoy & mumbai).\n", + "tags": [ + "NFT Spam Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + }, + { + "name": "tokenId", + "description": "String - The ID of the token. Can be in hex or decimal format.", + "in": "query", + "schema": { + "type": "string", + "default": "44" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "Returns whether the specified token is marked as an airdrop.", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "This object contains a boolean value indicating whether the token is an airdrop.", + "properties": { + "isAirdrop": { + "type": "boolean", + "description": "True - if the queried token is marked as an airdrop.\nFalse - if the queried token is not marked as an airdrop.\n" + } + } + } + } + } + } + }, + "operationId": "isAirdropNFT-v3" + } + }, + "/v3/{apiKey}/summarizeNFTAttributes": { + "get": { + "summary": "Attributes Summary By Contract", + "description": "Generates a summary of attribute prevalence for a specific NFT collection.\n\nPlease note that this endpoint is only available on Ethereum (mainnet) & Polygon (mainnet & mumbai).\n", + "tags": [ + "NFT Metadata Endpoints" + ], + "servers": [ + { + "url": "https://{network}.g.alchemy.com/nft", + "variables": { + "network": { + "enum": [ + "eth-mainnet", + "polygon-mainnet" + ], + "default": "eth-mainnet" + } + } + } + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "Returns a summary of attribute prevalence for the specified NFT collection.", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "Prevalence counts for each attribute within a collection.", + "properties": { + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "summary": { + "type": "object", + "description": "Object mapping trait types to the prevalence of each trait within that type." + }, + "contractAddress": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + } + } + }, + "examples": { + "summarizeNFTAttributes_response": { + "value": { + "summary": { + "Earrings": { + "WoW Coins": 437, + "Pizza Lovers": 188, + "Lucky Charms": 415, + "White Ovals": 210, + "Artist Palettes": 21, + "Queen's Emeralds": 206, + "Silver Drops": 822, + "Flower Power": 366, + "Pearls": 833, + "Spikes": 776, + "Yam's Fave": 381, + "Classic Hoops": 780, + "Ocean Hoops": 770, + "Triple Rings": 823, + "60s Fantasy": 399, + "Lightning Bolts": 226, + "Empresses Of Darkness": 103 + }, + "Necklace": { + "WoW Coin": 481, + "Malka": 494, + "Amazonite Energy": 490, + "Satin Choker": 721, + "Back To The 90s": 706, + "Empress of Darkness": 58, + "Spike Choker": 449, + "Golden Bib": 251, + "Golden Flakes": 710, + "Art Lover": 29, + "Rainbow": 474, + "Gold Ruler": 477, + "Wolf Pendant": 229, + "Tutti Frutti Beads": 691, + "Sun Keeper": 730 + }, + "Eyes": { + "Purple To The Left": 158, + "Heterochromia To The Left": 57, + "Brown To The Right": 455, + "Black Eye Roll": 881, + "Yellow To The Left": 141, + "Purple Eye Roll": 145, + "Green Straight": 433, + "Blue To The Left": 407, + "Green To The Right": 410, + "Black Straight": 794, + "Purple To The Right": 145, + "Black To The Right": 870, + "Green Eye Roll": 413, + "Yellow Straight": 128, + "Brown To The Left": 465, + "Brown Eye Roll": 416, + "Heterochromia To The Right": 76, + "Blue Straight": 415, + "Black To The Left": 877, + "Heterochromia Eye Roll": 85, + "Purple Straight": 158, + "Brown Straight": 434, + "Yellow Eye Roll": 141, + "Heterochromia Straight": 77, + "Yellow To The Right": 139, + "Blue To The Right": 416, + "Green To The Left": 424, + "Blue Eye Roll": 440 + }, + "Background": { + "Green Purple": 905, + "Purple Pink": 905, + "Dark Emerald": 924, + "Yellow Pink": 896, + "Pink Pastel": 849, + "Blue Green": 924, + "Soft Purple": 983, + "Green Orange": 907, + "Dark Purple": 876, + "Red Turquoise": 914, + "Orange Yellow": 917 + }, + "Mouth": { + "Cigarette": 502, + "Whistle": 868, + "Slight Smile": 1666, + "Stern": 1733, + "Countryside": 927, + "Huh": 506, + "Slightly Open": 1661, + "Bubble Gum": 404, + "Surprised": 1733 + }, + "Clothes": { + "80s Silk Shirt": 400, + "70s Shirt": 421, + "Fantasy Shirt": 542, + "Adventurer": 583, + "Striped Tee": 567, + "Naiade": 98, + "Tunic": 193, + "Checkmate": 396, + "Painter's Overall": 550, + "Witch Dress": 198, + "Little Red Dress": 437, + "Cabaret Corset": 535, + "Polka Dot Top": 573, + "Freedom Is Power Tee": 368, + "Warrior Armor": 177, + "Emerald Elven Cape": 117, + "Faux Fur Coat": 404, + "Red Leather Jacket": 374, + "White Tee": 533, + "Tuxedo": 100, + "Steampunk Octopus Top": 186, + "Queen's Dress": 391, + "Cherry Tee": 590, + "NFT Goddesses Top": 189, + "Gala Dress": 192, + "Psychedelic Dress": 492, + "Futuristic Dress": 394 + }, + "Facial Features": { + "Nose Piercing": 598, + "Red Eyeliner": 608, + "Leader": 224, + "Neck Tattoo": 227, + "Pearl Eyes": 207, + "Red Blue Bolt": 97, + "Rose Tattoo": 286, + "Feline Eyes": 590, + "Elven Warrior": 99, + "Marilyn": 633, + "Freckles": 581, + "Flashy Blue": 304, + "Sunset": 297, + "Heart Tattoo": 591, + "Rainbow": 578, + "Eyebrow Tattoo MMXXI": 303, + "Eye Scar": 308, + "Treble Bass Clef Tattoo": 210, + "Crystal Queen": 221, + "Antoinette": 582, + "Cyber Warrior": 120, + "Eyebrow Piercing": 619, + "Claw Scar": 236 + }, + "Hairstyle": { + "Badass Bob": 178, + "Curly Ponytail": 390, + "Finger Waves": 398, + "Colorful": 186, + "Fuchsia": 562, + "Retro": 408, + "Royal": 227, + "Boy Cut": 566, + "Bob": 653, + "Bun": 607, + "Long Dark": 416, + "Curly Pearl Updo": 122, + "Lucky Green": 417, + "Lioness": 600, + "Natural Red": 608, + "Double Buns": 182, + "Cotton Candy": 228, + "Rose Hair": 388, + "Purple Rainbow": 187, + "Lollipop": 612, + "Silver": 205, + "Braided Ponytail": 561, + "Platinum Pixie": 570, + "Black And White": 110, + "Feeling Turquoise": 412 + }, + "Lips Color": { + "Space": 195, + "Gold": 622, + "Purple": 1967, + "Burgundy": 1995, + "Party Pink": 1114, + "Passion Red": 3008, + "Flashy Blue": 1099 + }, + "Skin Tone": { + "Rainbow Bright": 197, + "Light Warm Yellow": 1021, + "Burning Red": 497, + "Cyber Green": 511, + "Night Goddess": 85, + "Deep Warm Gold": 1026, + "Light Medium Warm Gold": 997, + "Deep Bronze": 1047, + "Medium Olive": 976, + "Deep Neutral": 996, + "Medium Gold": 937, + "Light Warm Olive": 1031, + "Cool Blue": 486, + "Golden": 193 + }, + "Face Accessories": { + "Oversized Statement Sunglasses": 396, + "Psychedelic Sunglasses": 390, + "Resting Butterfly": 83, + "Red Round Sunglasses": 695, + "Classic Aviator WoW": 414, + "Black Mask": 398, + "Cateye Sunglasses": 221, + "On Fire": 116, + "70s Feels": 718, + "3D Glasses": 216, + "Round Glasses": 704, + "Black Round Retro": 403, + "Hypnotic Glasses": 209 + } + }, + "totalSupply": "10000", + "contractAddress": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + } + } + } + } + } + } + }, + "operationId": "summarizeNFTAttributes-v3" + } + }, + "/v3/{apiKey}/getFloorPrice": { + "get": { + "summary": "Floor Prices By Slug", + "description": "Retrieves the floor prices of an NFT collection across different marketplaces.\n\nPlease note that this endpoint is only available on Ethereum mainnet for Opensea & Looksrare marketplaces.\n", + "tags": [ + "NFT Sales Endpoints" + ], + "servers": [ + { + "url": "https://{network}.g.alchemy.com/nft", + "variables": { + "network": { + "enum": [ + "eth-mainnet" + ], + "default": "eth-mainnet" + } + } + } + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0x1f02bf9dde7c79137a08b2dd4fc964bfd2499734" + }, + "required": true + }, + { + "name": "collectionSlug", + "description": "String - OpenSea slug for the NFT collection.", + "in": "query", + "schema": { + "type": "string", + "default": "boredapeyachtclub" + }, + "required": false + } + ], + "responses": { + "200": { + "description": "Returns the floor prices of the specified NFT collection across different marketplaces.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "nftMarketplaceName": { + "type": "object", + "description": "Name of the NFT marketplace where the collection is listed (in camel case). Current marketplaces supported - `openSea`, `looksRare`. So instead of the word `nftMarketplaceName` you will see marketplace names like `openSea` here.", + "properties": { + "floorPrice": { + "type": "number", + "description": "Number - The floor price of the collection on the given marketplace." + }, + "priceCurrency": { + "type": "string", + "description": "String - The currency in which the floor price is denominated. Typically, denominated in ETH", + "enum": [ + "ETH" + ] + }, + "collectionUrl": { + "type": "string", + "description": "String - Link to the collection on the given marketplace." + }, + "retrievedAt": { + "type": "string", + "description": "String - UTC timestamp of when the floor price was retrieved from the marketplace." + }, + "error": { + "type": "string", + "description": "String - Returns the error `unable to fetch floor price` if there was an error fetching floor prices from the given marketplace." + } + } + } + } + } + } + } + } + }, + "operationId": "getFloorPrice-v3" + } + }, + "/v3/{apiKey}/searchContractMetadata": { + "get": { + "summary": "Search Contract Metadata", + "description": "Searches for a keyword across metadata of all ERC-721 and ERC-1155 smart contracts.\n\nThis endpoint is currently in BETA. If you have any questions or feedback, please contact us at support@alchemy.com or open a ticket in the dashboard.\n\nPlease note that this endpoint is only available on **Ethereum**, **Polygon**, **Arbitrum**, **Optimism** & **Base** networks.\n", + "tags": [ + "NFT Metadata Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "query", + "description": "String - The search string that you want to search for in contract metadata", + "in": "query", + "schema": { + "type": "string", + "default": "bored" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "Returns the list of NFT contracts where the metadata has one or more keywords from the search string.", + "content": { + "application/json": { + "schema": { + "type": "array", + "description": "List of contracts where the metadata contains one or more keywords from the search string.", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "String - Contract address for the queried NFT collection" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + } + } + } + } + } + } + } + }, + "operationId": "searchContractMetadata-v3" + } + }, + "/v3/{apiKey}/isHolderOfContract": { + "get": { + "summary": "Is Holder Of Contract", + "description": "isHolderOfContract - Determines whether a specific wallet holds any NFT from a given contract. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains).", + "tags": [ + "NFT Ownership Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "wallet", + "description": "String - Wallet address to check for contract ownership.", + "schema": { + "type": "string", + "default": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + }, + "in": "query", + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "Returns whether the specified wallet holds any NFT from the given contract.", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "Data related to a wallet's ownership of any token in an NFT contract.", + "properties": { + "isHolderOfContract": { + "type": "boolean", + "description": "Whether the given wallet owns any token in the given NFT contract." + } + } + } + } + } + } + }, + "operationId": "isHolderOfContract-v3" + } + }, + "/v3/{apiKey}/computeRarity": { + "get": { + "summary": "Attribute Rarity By NFT", + "description": "Calculates the rarity of each attribute within an NFT.\n\nPlease note that this endpoint is only available on Ethereum (mainnet) & Polygon (mainnet & mumbai).\n", + "tags": [ + "NFT Metadata Endpoints" + ], + "servers": [ + { + "url": "https://{network}.g.alchemy.com/nft", + "variables": { + "network": { + "enum": [ + "eth-mainnet", + "polygon-mainnet" + ], + "default": "eth-mainnet" + } + } + } + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + }, + { + "name": "tokenId", + "description": "String - The ID of the token. Can be in hex or decimal format.", + "in": "query", + "schema": { + "type": "string", + "default": "44" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "Returns the rarity information for each attribute of the specified NFT.", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "Object containing the rarity info of the collection.", + "properties": { + "rarities": { + "type": "array", + "description": "NFT attributes and their associated prevalence.", + "items": { + "type": "object", + "properties": { + "trait_type": { + "type": "string", + "description": "Name of the trait category, i.e., Hat, Color, Face, etc." + }, + "value": { + "type": "string", + "description": "Value for the trait, i.e., White Cap, Blue, Angry, etc." + }, + "prevalence": { + "type": "number", + "description": "Floating point value from 0 to 1 representing the prevalence of this value for this trait type." + } + } + } + } + } + } + } + } + } + }, + "operationId": "computeRarity-v3" + } + }, + "/v3/{apiKey}/getNFTSales": { + "get": { + "summary": "NFT Sales", + "description": "Retrieves NFT sales that have occurred through on-chain marketplaces.\n\nPlease note that this endpoint is only available on Ethereum (Seaport, Wyvern, X2Y2, Blur, LooksRare, Cryptopunks), Polygon (Seaport) & Optimism (Seaport) mainnets.\n", + "tags": [ + "NFT Sales Endpoints" + ], + "servers": [ + { + "url": "https://{network}.g.alchemy.com/nft", + "variables": { + "network": { + "enum": [ + "eth-mainnet", + "polygon-mainnet", + "opt-mainnet" + ], + "default": "eth-mainnet" + } + } + } + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "fromBlock", + "description": "String - The block number to start fetching NFT sales data from. Allowed values are decimal and hex integers, and \"latest\". Defaults to \"0\".", + "in": "query", + "schema": { + "type": "string", + "default": "0" + } + }, + { + "name": "toBlock", + "description": "String - The block number to start fetching NFT sales data from. Allowed values are decimal and hex integers, and \"latest\". Defaults to \"latest\".", + "in": "query", + "schema": { + "type": "string", + "default": "latest" + } + }, + { + "name": "order", + "description": "Enum - Whether to return the results ascending from startBlock or descending from startBlock. Defaults to descending (false).", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc" + } + }, + { + "name": "marketplace", + "description": "Enum - The name of the NFT marketplace to filter sales by. The endpoint currently supports \"seaport\", \"wyvern\", \"looksrare\", \"x2y2\", \"blur\", and \"cryptopunks\". Defaults to returning sales from all supported marketplaces.", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "seaport", + "looksrare", + "x2y2", + "wyvern", + "blur", + "cryptopunks" + ] + }, + "required": false + }, + { + "description": "String - The contract address of an NFT collection to filter sales by. Defaults to returning all NFT contracts.", + "name": "contractAddress", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "description": "String - The token ID of an NFT within the collection specified by contractAddress to filter sales by. Defaults to returning all token IDs.", + "name": "tokenId", + "in": "query", + "schema": { + "type": "string", + "default": "44" + }, + "required": false + }, + { + "name": "buyerAddress", + "description": "String - The address of the NFT buyer to filter sales by. Defaults to returning sales involving any buyer.", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "sellerAddress", + "description": "String - The address of the NFT seller to filter sales by. Defaults to returning sales involving any seller.", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "taker", + "description": "Enum - Filter by whether the buyer or seller was the taker in the NFT trade. Allowed filter values are \"BUYER\" and \"SELLER\". Defaults to returning both buyer and seller taker trades.", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "BUYER", + "SELLER" + ] + }, + "required": false + }, + { + "description": "Integer - The maximum number of NFT sales to return. Maximum and default values are 1000.", + "name": "limit", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "pageKey", + "description": "String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results.", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "responses": { + "200": { + "description": "Returns a list of NFT sales that match the query parameters.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "nftSales": { + "description": "List of NFT sales that match the query.", + "type": "array", + "items": { + "type": "object", + "properties": { + "marketplace": { + "type": "string", + "description": "String - The marketplace the sale took place on." + }, + "marketplaceAddress": { + "type": "string", + "description": "String - The address of the marketplace contract." + }, + "contractAddress": { + "type": "string", + "description": "String - The contract address of the collection the NFT belongs to." + }, + "tokenId": { + "type": "string", + "description": "String - The decimal token ID of the NFT being sold." + }, + "quantity": { + "type": "string", + "description": "Integer - The number of tokens sold in the sale as a decimal integer string." + }, + "buyerAddress": { + "type": "string", + "description": "String - The address of the buyer in the NFT sale." + }, + "sellerAddress": { + "type": "string", + "description": "String - The address of the seller in the NFT sale." + }, + "taker": { + "type": "string", + "description": "String - Whether the price taker in the trade was the buyer or the seller.", + "enum": [ + "BUYER", + "SELLER" + ] + }, + "sellerFee": { + "type": "object", + "description": "The payment from buyer to the seller.", + "properties": { + "amount": { + "type": "string", + "description": "String - The amount of the payment from the buyer to seller as a decimal integer string." + }, + "tokenAddress": { + "type": "string", + "description": "String - The smart contract address of the token used for the payment." + }, + "symbol": { + "type": "string", + "description": "String - The symbol of the token used for the payment." + }, + "decimals": { + "type": "integer", + "description": "Integer - The number of decimals of the token used for the payment." + } + } + }, + "protocolFee": { + "type": "object", + "description": "The payment from buyer to the NFT marketplace protocol.", + "properties": { + "amount": { + "type": "string", + "description": "String - The amount of the payment to the marketplace as a decimal integer string." + }, + "tokenAddress": { + "type": "string", + "description": "String - The smart contract address of the token used for the payment." + }, + "symbol": { + "type": "string", + "description": "String - The symbol of the token used for the payment." + }, + "decimals": { + "type": "integer", + "description": "Integer - The number of decimals of the token used for the payment." + } + } + }, + "royaltyFee": { + "type": "object", + "description": "The payment from buyer to the royalty address of the NFT collection.", + "properties": { + "amount": { + "type": "string", + "description": "String - The amount of the payment to the royalty collector as a decimal integer string." + }, + "tokenAddress": { + "type": "string", + "description": "String - The smart contract address of the token used for the payment." + }, + "symbol": { + "type": "string", + "description": "String - The symbol of the token used for the payment." + }, + "decimals": { + "type": "integer", + "description": "Integer - The number of decimals of the token used for the payment." + } + } + }, + "blockNumber": { + "type": "integer", + "description": "Integer - The block number the NFT sale took place in." + }, + "logIndex": { + "type": "integer", + "description": "Integer - The log number of the sale event emitted within the block." + }, + "bundleIndex": { + "type": "integer", + "description": "Integer - The index of the token within the bundle of NFTs sold in the sale." + }, + "transactionHash": { + "type": "string", + "description": "String - The transaction hash of the transaction containing the sale." + } + } + } + }, + "pageKey": { + "type": "string", + "description": "String - The page key to use to fetch the next page of results. Returns null if there are no more results." + }, + "validAt": { + "type": "object", + "description": "Block Information of the block as of which the corresponding data is valid", + "properties": { + "blockNumber": { + "type": "integer", + "description": "The block number above information is valid as of" + }, + "blockHash": { + "type": "string", + "description": "The block hash above information is valid as of" + }, + "blockTimestamp": { + "type": "string", + "description": "The block timestamp above information is valid as of" + } + } + } + } + }, + "examples": { + "nftSales_response": { + "summary": "Response (with pagination)", + "value": { + "nftSales": [ + { + "marketplace": "seaport", + "contractAddress": "0x49cf6f5d44e70224e2e23fdcdd2c053f30ada28b", + "tokenId": "13749", + "quantity": "1", + "buyerAddress": "0x78f6c2458b53d0735208992c693bb2b2dafebb52", + "sellerAddress": "0x558a18f94cabdea4e47c5965384f457d8e870419", + "taker": "BUYER", + "sellerFee": { + "amount": "11100000000000000000", + "symbol": "ETH", + "decimals": 18 + }, + "protocolFee": { + "amount": "300000000000000000", + "symbol": "ETH", + "decimals": 18 + }, + "royaltyFee": { + "amount": "600000000000000000", + "symbol": "ETH", + "decimals": 18 + }, + "blockNumber": 15000002, + "logIndex": 130, + "bundleIndex": 0, + "transactionHash": "0xecfa1b29c9016bd2556fde637c6b48484eeb14f273af54c49317e3856ab7cb16" + }, + { + "marketplace": "looksrare", + "contractAddress": "0x34d85c9cdeb23fa97cb08333b511ac86e1c4e258", + "tokenId": "75417", + "quantity": "1", + "buyerAddress": "0xb3aa9923489bc2bfec323bf05346acd4afbc92a0", + "sellerAddress": "0x206ccba024c236dced07c35b4e9eb0bade7ef166", + "taker": "BUYER", + "sellerFee": { + "amount": "2222700000000000000", + "symbol": "WETH", + "decimals": 18 + }, + "protocolFee": { + "amount": "47800000000000000", + "symbol": "WETH", + "decimals": 18 + }, + "royaltyFee": { + "amount": "119500000000000000", + "symbol": "WETH", + "decimals": 18 + }, + "blockNumber": 15000002, + "logIndex": 197, + "bundleIndex": 0, + "transactionHash": "0x4c23163e4f855e143e573776bc6129bee370dff6ce760e71553fc93201b292e2" + } + ], + "pageKey": "MTUwMDAwNzgsODcsMA", + "validAt": { + "blockNumber": 17091500, + "blockHash": "0x2a34a65c4e0cd7fdf187d6a497214ad2bee255d2d3501868a6b8c09b4d1261bd", + "blockTimestamp": "2023-04-21T01:25:59Z" + } + } + } + } + } + } + } + }, + "operationId": "getNFTSales-v3" + } + }, + "/v3/{apiKey}/getContractsForOwner": { + "get": { + "summary": "Contracts By Owner", + "description": "getContractsForOwner - Retrieves all NFT contracts held by a specified owner address.", + "tags": [ + "NFT Ownership Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "owner", + "description": "String - Address for NFT owner (can be in ENS format for Eth Mainnet).", + "schema": { + "type": "string", + "default": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + }, + "in": "query", + "required": true + }, + { + "name": "pageKey", + "description": "String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results.", + "schema": { + "type": "string" + }, + "in": "query" + }, + { + "name": "pageSize", + "description": "Number of NFTs to be returned per page. Defaults to 100. Max is 100.", + "schema": { + "type": "integer", + "default": 100 + }, + "in": "query" + }, + { + "name": "withMetadata", + "description": "Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "schema": { + "type": "boolean", + "default": true + }, + "in": "query" + }, + { + "name": "includeFilters[]", + "description": "Array of filters (as ENUMS) that will be applied to the query. Only NFTs that match one or more of these filters will be included in the response. May not be used in conjunction with excludeFilters[]. Filter Options:\n - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**.\n - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only.\n - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts)", + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "in": "query" + }, + { + "name": "excludeFilters[]", + "description": "Array of filters (as ENUMS) that will be applied to the query. NFTs that match one or more of these filters will be excluded from the response. May not be used in conjunction with includeFilters[]. Filter Options:\n - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**.\n - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only.\n - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts)", + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "in": "query" + }, + { + "name": "orderBy", + "description": "Enum - ordering scheme to use for ordering NFTs in the response. If unspecified, NFTs will be ordered by contract address and token ID.\n - transferTime: NFTs will be ordered by the time they were transferred into the wallet, with newest NFTs first. Note: This ordering is supported on Ethereum Mainnet, Optimism Mainnet, Polygon Mainnet, Base Mainnet, Arbitrum One, Polygon Amoy, Base Sepolia, Arbitrum Sepolia, Ethereum Sepolia, and Optimism Sepolia.", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "transferTime" + ] + }, + "required": false + }, + { + "name": "spamConfidenceLevel", + "description": "Enum - the confidence level at which to filter spam at.\n\nConfidence Levels:\n - VERY_HIGH\n - HIGH\n - MEDIUM\n - LOW\n\nThe confidence level set means that any spam that is at that confidence level or higher will be filtered out. For example, if the confidence level is HIGH, contracts that we have HIGH or VERY_HIGH confidence in being spam will be filtered out from the response. \nDefaults to VERY_HIGH for Ethereum Mainnet and MEDIUM for Matic Mainnet.\n\n**Please note that this filter is only available on paid tiers. Upgrade your account [here](https://dashboard.alchemy.com/settings/billing/).**", + "schema": { + "type": "string", + "enum": [ + "VERY_HIGH", + "HIGH", + "MEDIUM", + "LOW" + ] + }, + "in": "query", + "required": false + } + ], + "responses": { + "200": { + "description": "Returns a list of NFT contracts held by the specified owner address.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "contracts": { + "type": "array", + "items": { + "type": "object", + "description": "The object that represents a smart contract and has all data corresponding to that contract", + "properties": { + "address": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "name": { + "description": "The name of the contract, i.e. \"Bored Ape Yacht Club\".", + "type": "string" + }, + "symbol": { + "description": "The symbol of the contract, i.e. BAYC.", + "type": "string" + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string" + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + }, + "totalBalance": { + "type": "number", + "description": "Sum of NFT balances across all token IDs held by the owner. For non-fungible tokens this will be equal to the `numDistinctTokensOwned`, but it may be higher if the user holds some fungible ERC1155 tokens." + }, + "numDistinctTokensOwned": { + "type": "number", + "description": "Number of distinct token IDs held by the owner. For non-fungible tokens this will be equal to the `totalBalance`, but it may be lower if the user holds some fungible ERC1155 tokens." + }, + "isSpam": { + "type": "boolean", + "description": "`True` if the contract is detected as spam contract. `False` if it is not spam or has not been evaluated by our system yet" + }, + "displayNft": { + "type": "object", + "description": "Details of the display NFT for this contract. This NFT and its image can be used to represent the contract when displaying info about it.", + "properties": { + "tokenId": { + "description": "One of the tokens from this contract held by the owner.", + "type": "string" + }, + "name": { + "description": "The title of the token held by the owner i.e. \"Something #22\".", + "type": "string" + } + } + }, + "image": { + "type": "object", + "description": "Details of the image corresponding to this contract", + "properties": { + "cachedUrl": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "thumbnailUrl": { + "type": "string", + "description": "The Url that has the thumbnail version of the NFT" + }, + "pngUrl": { + "type": "string", + "description": "The Url that has the NFT image in png" + }, + "contentType": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "size": { + "type": "integer", + "description": "The size of the media asset in bytes." + }, + "originalUrl": { + "type": "string", + "description": "The original Url of the image coming straight from the smart contract" + } + } + } + } + } + }, + "pageKey": { + "type": "string" + }, + "totalCount": { + "type": "string", + "description": "String - Total number of NFT contracts held by the given address returned in this page." + } + } + }, + "examples": { + "withoutMetadata": { + "summary": "Response (withMetadata = false)", + "value": { + "contracts": [ + { + "address": "0x000386e3f7559d9b6a2f5c46b4ad1a9587d59dc3", + "totalBalance": 912, + "numDistinctTokensOwned": 80, + "isSpam": true, + "tokenId": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "address": "0x0015f391949f25c3211063104ad4afc99210f85c", + "totalBalance": 17, + "numDistinctTokensOwned": 6, + "isSpam": true, + "tokenId": "0x0000000000000000000000000000000000000000000000000000000000000002" + }, + { + "address": "0x005b92d71a934dbe48e985b6469881cf4b0308fc", + "totalBalance": 1, + "numDistinctTokensOwned": 1, + "isSpam": true, + "tokenId": "0x0000000000000000000000000000000000000000000000000000000000000003" + } + ], + "totalCount": 2120, + "pageKey": "20ef9df5-0d81-42e5-b741-140f595a407b" + } + }, + "withMetadata": { + "summary": "Response (withMetadata = true)", + "value": { + "contracts": [ + { + "address": "0x1C310c2fbB0D9755A6b918F990bC8D3504f2c684", + "name": "The Wonderful Husl Founder Cards", + "symbol": "The Wonderful Husl Founder Cards", + "totalSupply": null, + "tokenType": "ERC1155", + "contractDeployer": "0x0bdD0AEC835F92a465290cdd57b27FBd00376F53", + "deployedBlockNumber": 15664554, + "openSeaMetadata": { + "floorPrice": null, + "collectionName": "The Wonderful Husl Founder Cards", + "safelistRequestStatus": "not_requested", + "imageUrl": "https://i.seadn.io/gcs/files/754e38769c80c9d6188444dddb10ec80.png?w=500&auto=format", + "description": "[Husl](https://www.huslnft.xyz) is building the bridge between business and NFTs. Husl Founders are the driven, the passionate and the focused members of the community ready to change their future. Owning a Founders Card gets you exclusive perks, early access to business management, and discounts on managed services for your business as NFT. [Learn More](https://www.huslnft.xyz)", + "externalUrl": "https://www.huslnft.xyz", + "twitterUsername": null, + "discordUrl": null, + "lastIngestedAt": "2023-03-20T01:36:19.000Z" + }, + "totalBalance": "1", + "numDistinctTokensOwned": "1", + "isSpam": true, + "displayNft": { + "tokenId": "233", + "name": null + }, + "image": { + "cachedUrl": "https://nft-cdn.alchemy.com/eth-mainnet/d08d0d0fac8edf36ea09eae34b332814", + "thumbnailUrl": "https://res.cloudinary.com/alchemyapi/image/upload/thumbnailv2/eth-mainnet/d08d0d0fac8edf36ea09eae34b332814", + "pngUrl": "https://res.cloudinary.com/alchemyapi/image/upload/convert-png/eth-mainnet/d08d0d0fac8edf36ea09eae34b332814", + "contentType": "video/mp4", + "size": 36190302, + "originalUrl": "https://ipfs.io/ipfs/QmX2mM8r33W7KUBQSWXFAKNC2t654EXmWiX9vkrfrEaEnS" + } + } + ], + "totalCount": 2120, + "pageKey": "03949322-9b2c-4fdd-aab6-1369e29fa5b2" + } + } + } + } + } + } + }, + "operationId": "getContractsForOwner-v3" + } + }, + "/v3/{apiKey}/getCollectionsForOwner": { + "get": { + "summary": "Collections By Owner", + "description": "Retrieves all NFT collections held by a specified owner address.\n\nThis endpoint is only supported on Ethereum. Use `getContractsForOwner` for support across all other chains we support!\n", + "tags": [ + "NFT Ownership Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "owner", + "description": "String - Address for NFT owner (can be in ENS format for Eth Mainnet).", + "schema": { + "type": "string", + "default": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + }, + "in": "query", + "required": true + }, + { + "name": "pageKey", + "description": "String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results.", + "schema": { + "type": "string" + }, + "in": "query" + }, + { + "name": "pageSize", + "description": "Number of NFTs to be returned per page. Defaults to 100. Max is 100.", + "schema": { + "type": "integer", + "default": 100 + }, + "in": "query" + }, + { + "name": "withMetadata", + "description": "Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "schema": { + "type": "boolean", + "default": true + }, + "in": "query" + }, + { + "name": "includeFilters[]", + "description": "Array of filters (as ENUMS) that will be applied to the query. Only NFTs that match one or more of these filters will be included in the response. May not be used in conjunction with excludeFilters[]. Filter Options:\n - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**.\n - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only.\n - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts)", + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "in": "query" + }, + { + "name": "excludeFilters[]", + "description": "Array of filters (as ENUMS) that will be applied to the query. NFTs that match one or more of these filters will be excluded from the response. May not be used in conjunction with includeFilters[]. Filter Options:\n - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**.\n - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only.\n - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts)", + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "in": "query" + } + ], + "responses": { + "200": { + "description": "Returns a list of NFT collections held by the specified owner address.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "collections": { + "type": "array", + "items": { + "type": "object", + "description": "Metadata for an NFT collection held by an owner address. Includes general metadata about the collection, as well as information specific to the owner such as the total balance and the token ID of a random NFT for display purposes.", + "properties": { + "name": { + "description": "The name of the collection, i.e. \"Bored Ape Yacht Club\".", + "type": "string" + }, + "slug": { + "description": "The human-readable string used to identify the collection on OpenSea.", + "type": "string" + }, + "floorPrice": { + "type": "object", + "description": "Floor price data for the collection", + "properties": { + "marketplace": { + "description": "The marketplace the floor price is on", + "type": "string" + }, + "floorPrice": { + "description": "Floor price of the collection on the marketplace", + "type": "number" + }, + "priceCurrency": { + "description": "The currency of the floor price", + "type": "string" + } + } + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "contract": { + "type": "object", + "description": "Contract-level data for a collection, such as contract type, name, and symbol.", + "properties": { + "address": { + "description": "Address of the contract", + "type": "string" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + } + } + }, + "totalBalance": { + "type": "number", + "description": "Sum of NFT balances across all token IDs held by the owner. For non-fungible tokens this will be equal to the `numDistinctTokensOwned`, but it may be higher if the user holds some fungible ERC1155 tokens." + }, + "numDistinctTokensOwned": { + "type": "number", + "description": "Number of distinct token IDs held by the owner. For non-fungible tokens this will be equal to the `totalBalance`, but it may be lower if the user holds some fungible ERC1155 tokens." + }, + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "displayNft": { + "type": "object", + "description": "Details of the display NFT for this contract. This NFT and its image can be used to represent the contract when displaying info about it.", + "properties": { + "tokenId": { + "description": "One of the tokens from this contract held by the owner.", + "type": "string" + }, + "name": { + "description": "The title of the token held by the owner i.e. \"Something #22\".", + "type": "string" + } + } + }, + "image": { + "type": "object", + "description": "Details of the image corresponding to this contract", + "properties": { + "cachedUrl": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "thumbnailUrl": { + "type": "string", + "description": "The Url that has the thumbnail version of the NFT" + }, + "pngUrl": { + "type": "string", + "description": "The Url that has the NFT image in png" + }, + "contentType": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "size": { + "type": "integer", + "description": "The size of the media asset in bytes." + }, + "originalUrl": { + "type": "string", + "description": "The original Url of the image coming straight from the smart contract" + } + } + } + } + } + }, + "pageKey": { + "type": "string" + }, + "totalCount": { + "type": "string", + "description": "String - Total number of NFT collections held by the given address." + } + } + }, + "examples": { + "withoutMetadata": { + "summary": "Response (withMetadata = false)", + "value": { + "collections": [ + { + "address": "0x3a5051566b2241285BE871f650C445A88A970edd", + "name": "The Humanoids ", + "slug": "thehumanoids", + "totalBalance": "1", + "numDistinctTokensOwned": "1", + "isSpam": false + } + ], + "totalCount": 2120, + "pageKey": "20ef9df5-0d81-42e5-b741-140f595a407b" + } + }, + "withMetadata": { + "summary": "Response (withMetadata = true)", + "value": { + "collections": [ + { + "name": "The Humanoids", + "slug": "thehumanoids", + "floorPrice": { + "marketplace": "seaport", + "floorPrice": 0.37, + "priceCurrency": "ETH" + }, + "description": "The Humanoids (Gen 1) is a collection of 10,000 unique 3D 4K personalities.\n\n[GEN 1.1 (CUSTOMIZABLE PFP)](https://opensea.io/collection/the-humanoids-gen-1-1/) | [DISCORD](https://discord.gg/thehumanoids) | [TWITTER](https://twitter.com/thehumanoids)\n\nStake your Gen 1 Humanoid and earn $ION to customize Gen 1.1 Humanoids using our proprietary Trait Factory.\n\nNote: Holder Count is inaccurate as Humanoids are currently being staked.", + "externalUrl": "http://thehumanoids.com", + "twitterUsername": "thehumanoids", + "discordUrl": "https://discord.gg/thehumanoids", + "contract": { + "address": "0x3a5051566b2241285BE871f650C445A88A970edd", + "name": "The Humanoids ", + "symbol": "HMNDS", + "tokenType": "ERC721", + "contractDeployer": "0xB8256c1c6654cedb9607644b07deC91Ca15fb9f6", + "deployedBlockNumber": 13313830 + }, + "totalBalance": "1", + "numDistinctTokensOwned": "1", + "isSpam": false, + "displayNft": { + "tokenId": "5880", + "name": "Humanoid #5880" + }, + "image": { + "cachedUrl": "https://nft-cdn.alchemy.com/eth-mainnet/57dab2f078ca70e310c387064f66daaa", + "thumbnailUrl": "https://res.cloudinary.com/alchemyapi/image/upload/thumbnailv2/eth-mainnet/57dab2f078ca70e310c387064f66daaa", + "pngUrl": "https://res.cloudinary.com/alchemyapi/image/upload/convert-png/eth-mainnet/57dab2f078ca70e310c387064f66daaa", + "contentType": "image/jpeg", + "size": 1898134, + "originalUrl": "https://ipfs.io/ipfs/QmcjYgWMokcqnaSGZ31GVbGDe9V9z1KeNerRGfgeBEkn4k/5880.jpg" + } + } + ], + "totalCount": 2120, + "pageKey": "03949322-9b2c-4fdd-aab6-1369e29fa5b2" + } + } + } + } + } + } + }, + "operationId": "getCollectionsForOwner-v3" + } + }, + "/v3/{apiKey}/reportSpam": { + "get": { + "summary": "Report Spam Address", + "description": "Reports a specific address to the API if it is suspected to be spam.\n\nSpam NFT functionality is available on Mainnet for the following chains: Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast. More to come soon!\n", + "tags": [ + "NFT Spam Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "address", + "description": "String - The address to check for spam status.", + "in": "query", + "schema": { + "type": "string", + "default": "0x495f947276749ce646f68ac8c248420045cb7b5e" + }, + "required": true + }, + { + "name": "isSpam", + "in": "query", + "required": true, + "schema": { + "type": "boolean", + "description": "Whether the address is spam.", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Returns a confirmation message if the address was successfully reported as spam.", + "content": { + "application/json": { + "schema": { + "type": "string", + "description": "String - \"Address was successfully reported as spam\" if calling the API was successful." + } + } + } + } + }, + "operationId": "reportSpam-v3" + } + }, + "/v3/{apiKey}/refreshNftMetadata": { + "post": { + "summary": "Refresh NFT Metadata", + "description": "Submits a request for Alchemy to refresh the cached metadata of a specific NFT token.\n\nPlease note that this endpoint is only supported on Ethereum (Mainnet & Sepolia), Polygon (Mainnet, Mumbai & Amoy), Arbitrum One (mainnet), Optimism (mainnet) & Base (mainnet). For other chains, you could use the `getNFTMetadata` endpoint with the `refreshCache` parameter set to `true` to refresh the metadata!\n", + "tags": [ + "NFT Metadata Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "contractAddress", + "tokenId" + ], + "properties": { + "contractAddress": { + "type": "string", + "description": "Contract address of the token you want to refresh.", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "tokenId": { + "type": "string", + "description": "Token ID of the token you want to refresh. Must belong to the contract address.", + "default": "44" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Returns the status of the refresh request along with the estimated time to complete.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "string", + "description": "If the token is successfully queued for ingestion the value will be \"Queued\"." + }, + "estimatedMsToRefresh": { + "type": "string", + "description": "Estimated time until the metadata refresh is complete for this token." + } + } + }, + "examples": { + "byDefault": { + "summary": "Successful Response", + "value": { + "status": "Queued", + "estimatedMsToRefresh": 10000 + } + } + } + } + } + } + }, + "operationId": "refreshNftMetadata-v3" + } + }, + "/v2/{apiKey}/getNFTs": { + "get": { + "summary": "getNFTs", + "description": "Gets all NFTs currently owned by a given address.", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "parameters": [ + { + "name": "owner", + "description": "String - Address for NFT owner (can be in ENS format for Eth Mainnet).", + "schema": { + "type": "string", + "default": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + }, + "in": "query", + "required": true + }, + { + "name": "contractAddresses[]", + "description": "Array of contract addresses to filter the responses with. Max limit 45 contracts.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + }, + "in": "query" + }, + { + "name": "withMetadata", + "description": "Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "schema": { + "type": "boolean", + "default": true + }, + "in": "query" + }, + { + "name": "orderBy", + "description": "Enum - ordering scheme to use for ordering NFTs in the response. If unspecified, NFTs will be ordered by contract address and token ID.\n - transferTime: NFTs will be ordered by the time they were transferred into the wallet, with newest NFTs first. Note: This ordering is supported on Ethereum Mainnet, Optimism Mainnet, Polygon Mainnet, Base Mainnet, Arbitrum One, Polygon Amoy, Base Sepolia, Arbitrum Sepolia, Ethereum Sepolia, and Optimism Sepolia.", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "transferTime" + ] + }, + "required": false + }, + { + "name": "excludeFilters[]", + "description": "Array of filters (as ENUMS) that will be applied to the query. NFTs that match one or more of these filters will be excluded from the response. May not be used in conjunction with includeFilters[]. Filter Options:\n - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**.\n - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only.\n - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts)", + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "in": "query" + }, + { + "name": "includeFilters[]", + "description": "Array of filters (as ENUMS) that will be applied to the query. Only NFTs that match one or more of these filters will be included in the response. May not be used in conjunction with excludeFilters[]. Filter Options:\n - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**.\n - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only.\n - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts)", + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "in": "query" + }, + { + "name": "spamConfidenceLevel", + "description": "Enum - the confidence level at which to filter spam at.\n\nConfidence Levels:\n - VERY_HIGH\n - HIGH\n - MEDIUM\n - LOW\n\nThe confidence level set means that any spam that is at that confidence level or higher will be filtered out. For example, if the confidence level is HIGH, contracts that we have HIGH or VERY_HIGH confidence in being spam will be filtered out from the response. \nDefaults to VERY_HIGH for Ethereum Mainnet and MEDIUM for Matic Mainnet.\n\n**Please note that this filter is only available on paid tiers. Upgrade your account [here](https://dashboard.alchemy.com/settings/billing/).**", + "schema": { + "type": "string", + "enum": [ + "VERY_HIGH", + "HIGH", + "MEDIUM", + "LOW" + ] + }, + "in": "query", + "required": false + }, + { + "name": "tokenUriTimeoutInMs", + "description": "No set timeout by default - When metadata is requested, this parameter is the timeout (in milliseconds) for the website hosting the metadata to respond. If you want to _only_ access the cache and not live fetch any metadata for cache misses then set this value to 0.", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "pageKey", + "description": "String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results.", + "schema": { + "type": "string" + }, + "in": "query" + }, + { + "name": "pageSize", + "description": "Number of NFTs to be returned per page. Defaults to 100. Max is 100.", + "schema": { + "type": "integer", + "default": 100 + }, + "in": "query" + } + ], + "responses": { + "200": { + "description": "Returns the list of all NFTs owned by the given address and satisfying the given input parameters.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "ownedNfts": { + "type": "array", + "items": { + "type": "object", + "description": "The object that represents an NFT and has all data corresponding to that NFT", + "properties": { + "contract": { + "description": "Object - Contract for returned NFT", + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "String - Address of NFT contract." + } + } + }, + "id": { + "type": "object", + "properties": { + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenMetadata": { + "type": "object", + "properties": { + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + } + } + } + } + }, + "balance": { + "type": "string", + "description": "String - Token balance" + }, + "title": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Brief human-readable description" + }, + "tokenUri": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + } + } + }, + "media": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + }, + "thumbnail": { + "type": "string", + "description": "URL for a resized thumbnail of the NFT media asset." + }, + "format": { + "type": "string", + "description": "The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets." + }, + "bytes": { + "type": "integer", + "description": "The size of the media asset in bytes." + } + } + }, + "metadata": { + "type": "object", + "description": "Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually.", + "properties": { + "image": { + "type": "string", + "description": "String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces." + }, + "external_url": { + "type": "string", + "description": "String - The image URL that appears alongside the asset image on NFT platforms." + }, + "background_color": { + "type": "string", + "description": "String - Background color of the NFT item. Usually must be defined as a six-character hexadecimal." + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms)" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trait_type": { + "type": "string" + } + } + }, + "description": "Object - Traits/attributes/characteristics for each NFT asset." + }, + "media": { + "type": "array", + "items": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + }, + "thumbnail": { + "type": "string", + "description": "URL for a resized thumbnail of the NFT media asset." + }, + "format": { + "type": "string", + "description": "The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets." + }, + "bytes": { + "type": "integer", + "description": "The size of the media asset in bytes." + } + } + } + } + } + }, + "timeLastUpdated": { + "type": "string", + "description": "String - ISO timestamp of the last cache refresh for the information returned in the metadata field." + }, + "error": { + "type": "string", + "description": "String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT." + }, + "contractMetadata": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "opensea": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + } + } + }, + "spamInfo": { + "type": "object", + "description": "Information about whether and why a contract was marked as spam.", + "properties": { + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "spamClassifications": { + "description": "List of reasons why a contract was classified as spam. **Only available on paid tiers.**", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "acquiredAt": { + "type": "object", + "description": "Only present if the request specified `orderBy=transferTime`.", + "properties": { + "blockTimestamp": { + "type": "string", + "description": "Block timestamp of the block where the NFT was most recently acquired." + }, + "blockNumber": { + "type": "string", + "description": "Block number of the block where the NFT was most recently acquired." + } + } + } + } + } + }, + "pageKey": { + "type": "string" + }, + "totalCount": { + "type": "integer", + "description": "Integer - Total number of NFTs (distinct `tokenIds`) owned by the given address." + }, + "blockHash": { + "type": "string", + "description": "String - The canonical head block hash of when your request was received i.e. the block corresponding to `latest`" + } + } + }, + "examples": { + "byDefault": { + "summary": "Response (By Default)", + "value": { + "ownedNfts": [ + { + "contract": { + "address": "0x0beed7099af7514ccedf642cfea435731176fb02" + }, + "id": { + "tokenId": "28", + "tokenMetadata": { + "tokenType": "ERC721" + } + }, + "title": "DuskBreaker #28", + "description": "Breakers have the honor of serving humanity through their work on The Dusk. They are part of a select squad of 10,000 recruits who spend their days exploring a mysterious alien spaceship filled with friends, foes, and otherworldly technology.", + "tokenUri": { + "raw": "https://duskbreakers.gg/api/breakers/28", + "gateway": "https://duskbreakers.gg/api/breakers/28" + }, + "media": [ + { + "raw": "https://duskbreakers.gg/breaker_images/28.png", + "gateway": "https://duskbreakers.gg/breaker_images/28.png" + } + ], + "metadata": { + "name": "DuskBreaker #28", + "description": "Breakers have the honor of serving humanity through their work on The Dusk. They are part of a select squad of 10,000 recruits who spend their days exploring a mysterious alien spaceship filled with friends, foes, and otherworldly technology.", + "image": "https://duskbreakers.gg/breaker_images/28.png", + "external_url": "https://duskbreakers.gg", + "attributes": [ + { + "value": "Locust Rider Armor (Red)", + "trait_type": "Clothes" + }, + { + "value": "Big Smile (Purple)", + "trait_type": "Mouth" + }, + { + "value": "Yellow", + "trait_type": "Background" + } + ] + }, + "timeLastUpdated": "2022-02-16T22:52:54.719Z", + "contractMetadata": { + "name": "DuskBreakers", + "symbol": "DUSK", + "totalSupply": "10000", + "tokenType": "ERC721" + } + }, + { + "contract": { + "address": "0x97597002980134bea46250aa0510c9b90d87a587" + }, + "id": { + "tokenId": "5527", + "tokenMetadata": { + "tokenType": "ERC721" + } + }, + "title": "Runner #5527", + "description": "Chain Runners are Mega City renegades 100% generated on chain.", + "tokenUri": { + "raw": "https://api.chainrunners.xyz/tokens/metadata/5527?dna=73247164192459371523281785218958151913554625578441142916970699984935810987041", + "gateway": "https://api.chainrunners.xyz/tokens/metadata/5527?dna=73247164192459371523281785218958151913554625578441142916970699984935810987041" + }, + "media": [ + { + "raw": "https://img.chainrunners.xyz/api/v1/tokens/png/5527", + "gateway": "https://img.chainrunners.xyz/api/v1/tokens/png/5527" + } + ], + "metadata": { + "name": "Runner #5527", + "description": "Chain Runners are Mega City renegades 100% generated on chain.", + "image": "https://img.chainrunners.xyz/api/v1/tokens/png/5527", + "attributes": [ + { + "value": "Purple Green Diag", + "trait_type": "Background" + }, + { + "value": "Human", + "trait_type": "Race" + }, + { + "value": "Cig", + "trait_type": "Mouth Accessory" + } + ] + }, + "timeLastUpdated": "2022-02-18T00:42:04.401Z", + "contractMetadata": { + "name": "Chain Runners", + "symbol": "RUN", + "totalSupply": "10000", + "tokenType": "ERC721" + } + } + ], + "totalCount": 6, + "blockHash": "0xeb2d26af5b6175344a14091777535a2cb21c681665a734a8285f889981987630" + } + }, + "withoutMetadata": { + "summary": "Response (withMetadata = false)", + "value": { + "ownedNfts": [ + { + "contract": { + "address": "0x0beed7099af7514ccedf642cfea435731176fb02" + }, + "id": { + "tokenId": "0x000000000000000000000000000000000000000000000000000000000000001c" + } + }, + { + "contract": { + "address": "0x0beed7099af7514ccedf642cfea435731176fb02" + }, + "id": { + "tokenId": "0x000000000000000000000000000000000000000000000000000000000000001d" + }, + "balance": "1" + }, + { + "contract": { + "address": "0x97597002980134bea46250aa0510c9b90d87a587" + }, + "id": { + "tokenId": "0x0000000000000000000000000000000000000000000000000000000000001597" + }, + "balance": "1" + } + ], + "totalCount": 6, + "blockHash": "0xf9a2a4e15116680e22b160c734529f62d89d54cde0759daf5135672fad0ecebc" + } + }, + "withContractFiltering": { + "summary": "Response (with contract filtering)", + "value": { + "ownedNfts": [ + { + "contract": { + "address": "0x34d77a17038491a2a9eaa6e690b7c7cd39fc8392" + }, + "id": { + "tokenId": "0x0000000000000000000000000000000000000000000000000000000000000277" + } + } + ], + "totalCount": 1, + "blockHash": "0x3d8bca59c08e41f55d46ebbe738327eb12955cf280bd06ef7d40352919c188d8" + } + }, + "withPagination": { + "summary": "Response (with pagination)", + "value": { + "ownedNfts": [ + { + "contract": { + "address": "0x97597002980134bea46250aa0510c9b90d87a587" + }, + "id": { + "tokenId": "0x00000000000000000000000000000000000000000000000000000000000009cb" + } + }, + { + "contract": { + "address": "0x97597002980134bea46250aa0510c9b90d87a587" + }, + "id": { + "tokenId": "0x00000000000000000000000000000000000000000000000000000000000009cc" + } + }, + { + "contract": { + "address": "0x5ab21ec0bfa0b29545230395e3adaca7d552c948" + }, + "id": { + "tokenId": "0x00000000000000000000000000000000000000000000000000000000000006dc" + } + }, + { + "contract": { + "address": "0x3b3ee1931dc30c1957379fac9aba94d1c48a5405" + }, + "id": { + "tokenId": "0x000000000000000000000000000000000000000000000000000000000000001a" + } + }, + { + "contract": { + "address": "0x69c40e500b84660cb2ab09cb9614fa2387f95f64" + }, + "id": { + "tokenId": "0x0000000000000000000000000000000000000000000000000000000000000391" + } + }, + { + "contract": { + "address": "0x97597002980134bea46250aa0510c9b90d87a587" + }, + "id": { + "tokenId": "0x00000000000000000000000000000000000000000000000000000000000008d5" + } + }, + { + "contract": { + "address": "0x97597002980134bea46250aa0510c9b90d87a587" + }, + "id": { + "tokenId": "0x0000000000000000000000000000000000000000000000000000000000000a1d" + } + }, + { + "contract": { + "address": "0x97597002980134bea46250aa0510c9b90d87a587" + }, + "id": { + "tokenId": "0x000000000000000000000000000000000000000000000000000000000000002a" + } + }, + { + "contract": { + "address": "0x97597002980134bea46250aa0510c9b90d87a587" + }, + "id": { + "tokenId": "0x000000000000000000000000000000000000000000000000000000000000038e" + } + }, + { + "contract": { + "address": "0x97597002980134bea46250aa0510c9b90d87a587" + }, + "id": { + "tokenId": "0x000000000000000000000000000000000000000000000000000000000000244b" + } + } + ], + "pageKey": "88434286-7eaa-472d-8739-32a0497c2a18", + "totalCount": 277, + "blockHash": "0x94d5ab52b8a6571733f6b183ef89f31573b82a4e78f8129b0ce90ef0beaf208b" + } + } + } + } + } + } + }, + "operationId": "getNFTs" + } + }, + "/v2/{apiKey}/getNFTMetadata": { + "get": { + "summary": "getNFTMetadata", + "description": "Gets the metadata associated with a given NFT.", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + }, + { + "name": "tokenId", + "description": "String - The ID of the token. Can be in hex or decimal format.", + "in": "query", + "schema": { + "type": "string", + "default": "44" + }, + "required": true + }, + { + "name": "tokenType", + "description": "String - 'ERC721' or 'ERC1155'; specifies type of token to query for. API requests will perform faster if this is specified.", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "tokenUriTimeoutInMs", + "description": "No set timeout by default - When metadata is requested, this parameter is the timeout (in milliseconds) for the website hosting the metadata to respond. If you want to _only_ access the cache and not live fetch any metadata for cache misses then set this value to 0.", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "refreshCache", + "description": "Defaults to false for faster response times. If true will refresh metadata for given token. If false will check the cache and use it or refresh if cache doesn't exist.", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "The object that represents an NFT and has all data corresponding to that NFT", + "properties": { + "contract": { + "description": "Object - Contract for returned NFT", + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "String - Address of NFT contract." + } + } + }, + "id": { + "type": "object", + "properties": { + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenMetadata": { + "type": "object", + "properties": { + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + } + } + } + } + }, + "balance": { + "type": "string", + "description": "String - Token balance" + }, + "title": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Brief human-readable description" + }, + "tokenUri": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + } + } + }, + "media": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + }, + "thumbnail": { + "type": "string", + "description": "URL for a resized thumbnail of the NFT media asset." + }, + "format": { + "type": "string", + "description": "The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets." + }, + "bytes": { + "type": "integer", + "description": "The size of the media asset in bytes." + } + } + }, + "metadata": { + "type": "object", + "description": "Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually.", + "properties": { + "image": { + "type": "string", + "description": "String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces." + }, + "external_url": { + "type": "string", + "description": "String - The image URL that appears alongside the asset image on NFT platforms." + }, + "background_color": { + "type": "string", + "description": "String - Background color of the NFT item. Usually must be defined as a six-character hexadecimal." + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms)" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trait_type": { + "type": "string" + } + } + }, + "description": "Object - Traits/attributes/characteristics for each NFT asset." + }, + "media": { + "type": "array", + "items": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + }, + "thumbnail": { + "type": "string", + "description": "URL for a resized thumbnail of the NFT media asset." + }, + "format": { + "type": "string", + "description": "The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets." + }, + "bytes": { + "type": "integer", + "description": "The size of the media asset in bytes." + } + } + } + } + } + }, + "timeLastUpdated": { + "type": "string", + "description": "String - ISO timestamp of the last cache refresh for the information returned in the metadata field." + }, + "error": { + "type": "string", + "description": "String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT." + }, + "contractMetadata": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "opensea": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + } + } + }, + "spamInfo": { + "type": "object", + "description": "Information about whether and why a contract was marked as spam.", + "properties": { + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "spamClassifications": { + "description": "List of reasons why a contract was classified as spam. **Only available on paid tiers.**", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "acquiredAt": { + "type": "object", + "description": "Only present if the request specified `orderBy=transferTime`.", + "properties": { + "blockTimestamp": { + "type": "string", + "description": "Block timestamp of the block where the NFT was most recently acquired." + }, + "blockNumber": { + "type": "string", + "description": "Block number of the block where the NFT was most recently acquired." + } + } + } + } + } + } + } + } + }, + "operationId": "getNFTMetadata" + } + }, + "/v2/{apiKey}/getNFTMetadataBatch": { + "post": { + "summary": "getNFTMetadataBatch", + "description": "Gets the metadata associated with up to 100 given NFT contracts.", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "tokens" + ], + "properties": { + "tokens": { + "type": "array", + "description": "List of token objects to batch request NFT metadata for. Maximum 100.", + "items": { + "type": "object", + "required": [ + "contractAddress", + "tokenId" + ], + "properties": { + "contractAddress": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenType": { + "type": "string" + } + } + } + }, + "tokenUriTimeoutInMs": { + "type": "integer" + }, + "refreshCache": { + "type": "boolean", + "default": false + } + } + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "description": "The object that represents an NFT and has all data corresponding to that NFT", + "properties": { + "contract": { + "description": "Object - Contract for returned NFT", + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "String - Address of NFT contract." + } + } + }, + "id": { + "type": "object", + "properties": { + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenMetadata": { + "type": "object", + "properties": { + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + } + } + } + } + }, + "balance": { + "type": "string", + "description": "String - Token balance" + }, + "title": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Brief human-readable description" + }, + "tokenUri": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + } + } + }, + "media": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + }, + "thumbnail": { + "type": "string", + "description": "URL for a resized thumbnail of the NFT media asset." + }, + "format": { + "type": "string", + "description": "The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets." + }, + "bytes": { + "type": "integer", + "description": "The size of the media asset in bytes." + } + } + }, + "metadata": { + "type": "object", + "description": "Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually.", + "properties": { + "image": { + "type": "string", + "description": "String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces." + }, + "external_url": { + "type": "string", + "description": "String - The image URL that appears alongside the asset image on NFT platforms." + }, + "background_color": { + "type": "string", + "description": "String - Background color of the NFT item. Usually must be defined as a six-character hexadecimal." + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms)" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trait_type": { + "type": "string" + } + } + }, + "description": "Object - Traits/attributes/characteristics for each NFT asset." + }, + "media": { + "type": "array", + "items": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + }, + "thumbnail": { + "type": "string", + "description": "URL for a resized thumbnail of the NFT media asset." + }, + "format": { + "type": "string", + "description": "The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets." + }, + "bytes": { + "type": "integer", + "description": "The size of the media asset in bytes." + } + } + } + } + } + }, + "timeLastUpdated": { + "type": "string", + "description": "String - ISO timestamp of the last cache refresh for the information returned in the metadata field." + }, + "error": { + "type": "string", + "description": "String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT." + }, + "contractMetadata": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "opensea": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + } + } + }, + "spamInfo": { + "type": "object", + "description": "Information about whether and why a contract was marked as spam.", + "properties": { + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "spamClassifications": { + "description": "List of reasons why a contract was classified as spam. **Only available on paid tiers.**", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "acquiredAt": { + "type": "object", + "description": "Only present if the request specified `orderBy=transferTime`.", + "properties": { + "blockTimestamp": { + "type": "string", + "description": "Block timestamp of the block where the NFT was most recently acquired." + }, + "blockNumber": { + "type": "string", + "description": "Block number of the block where the NFT was most recently acquired." + } + } + } + } + } + } + } + } + } + }, + "operationId": "getNFTMetadataBatch" + } + }, + "/v2/{apiKey}/getContractMetadata": { + "get": { + "summary": "getContractMetadata", + "description": "Queries NFT high-level collection/contract level information.", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "String - Contract address for the queried NFT collection" + }, + "contractMetadata": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "opensea": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + } + } + } + } + } + } + } + } + }, + "operationId": "getContractMetadata" + } + }, + "/v2/{apiKey}/getContractMetadataBatch": { + "post": { + "summary": "getContractMetadataBatch", + "description": "Gets the metadata associated with the given list of contract addresses", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "contractAddresses": { + "type": "array", + "description": "list of contract addresses to batch metadata requests for", + "default": [ + "0xe785E82358879F061BC3dcAC6f0444462D4b5330", + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d" + ], + "items": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "contractMetadata": { + "type": "object", + "description": "The object that represents a smart contract and has all data corresponding to that contract", + "properties": { + "address": { + "description": "Address of the held contract", + "type": "string" + }, + "totalBalance": { + "type": "number", + "description": "Sum of NFT balances across all token IDs held by the owner. For non-fungible tokens this will be equal to the `numDistinctTokensOwned`, but it may be higher if the user holds some fungible ERC1155 tokens." + }, + "numDistinctTokensOwned": { + "type": "number", + "description": "Number of distinct token IDs held by the owner. For non-fungible tokens this will be equal to the `totalBalance`, but it may be lower if the user holds some fungible ERC1155 tokens." + }, + "isSpam": { + "type": "boolean" + }, + "tokenId": { + "description": "One of the tokens from this contract held by the owner.", + "type": "string" + }, + "name": { + "description": "The name of the contract, i.e. \"Bored Ape Yacht Club\".", + "type": "string" + }, + "title": { + "description": "The title of the token held by the owner i.e. \"Something #22\".", + "type": "string" + }, + "symbol": { + "description": "The symbol of the contract, i.e. BAYC.", + "type": "string" + }, + "tokenType": { + "description": "The NFT standard used by the contract, i.e. ERC721 or ERC1155.", + "type": "string" + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "media": { + "type": "array", + "items": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + }, + "thumbnail": { + "type": "string", + "description": "URL for a resized thumbnail of the NFT media asset." + }, + "format": { + "type": "string", + "description": "The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets." + }, + "bytes": { + "type": "integer", + "description": "The size of the media asset in bytes." + } + } + } + }, + "opensea": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + } + } + } + } + } + } + } + } + } + }, + "operationId": "getContractMetadataBatch" + } + }, + "/v2/{apiKey}/getNFTsForCollection": { + "get": { + "summary": "getNFTsForCollection", + "description": "Gets all NFTs for a given NFT contract.", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "collectionSlug", + "description": "String - OpenSea slug for the NFT collection.", + "in": "query", + "schema": { + "type": "string", + "default": "boredapeyachtclub" + }, + "required": false + }, + { + "name": "withMetadata", + "description": "Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "schema": { + "type": "boolean", + "default": true + }, + "in": "query" + }, + { + "name": "startToken", + "description": "String - A tokenID offset used for pagination. Can be a hex string, or a decimal. Users can specify the offset themselves to start from a custom offset, or to fetch multiple token ranges in parallel.", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "description": "Integer - Sets the total number of NFTs returned in the response. Defaults to 100.", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "tokenUriTimeoutInMs", + "description": "No set timeout by default - When metadata is requested, this parameter is the timeout (in milliseconds) for the website hosting the metadata to respond. If you want to _only_ access the cache and not live fetch any metadata for cache misses then set this value to 0.", + "in": "query", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "nfts": { + "description": "List of objects that represent NFTs stored under the queried contract address or collection slug.", + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "object", + "properties": { + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenMetadata": { + "type": "object", + "properties": { + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + } + } + } + } + }, + "tokenUri": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + } + } + }, + "metadata": { + "type": "object", + "description": "Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually.", + "properties": { + "image": { + "type": "string", + "description": "String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces." + }, + "external_url": { + "type": "string", + "description": "String - The image URL that appears alongside the asset image on NFT platforms." + }, + "background_color": { + "type": "string", + "description": "String - Background color of the NFT item. Usually must be defined as a six-character hexadecimal." + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms)" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trait_type": { + "type": "string" + } + } + }, + "description": "Object - Traits/attributes/characteristics for each NFT asset." + }, + "media": { + "type": "array", + "items": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + }, + "thumbnail": { + "type": "string", + "description": "URL for a resized thumbnail of the NFT media asset." + }, + "format": { + "type": "string", + "description": "The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets." + }, + "bytes": { + "type": "integer", + "description": "The size of the media asset in bytes." + } + } + } + } + } + }, + "timeLastUpdated": { + "type": "string", + "description": "String - ISO timestamp of the last cache refresh for the information returned in the metadata field." + }, + "contractMetadata": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "opensea": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + } + } + } + } + } + }, + "nextToken": { + "type": "string", + "description": "String - An offset used for pagination. Can be passed back as the \"startToken\" of a subsequent request to get the next page of results. Absent if there are no more results." + } + } + } + } + } + } + }, + "operationId": "getNFTsForCollection" + } + }, + "/v2/{apiKey}/getOwnersForToken": { + "get": { + "summary": "getOwnersForToken", + "description": "Get the owner(s) for a token.", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the token to get the owner for.", + "in": "query", + "schema": { + "type": "string", + "default": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" + }, + "required": true + }, + { + "name": "tokenId", + "description": "String - The ID of the token. Can be in hex or decimal format.", + "in": "query", + "schema": { + "type": "string", + "default": "44" + }, + "required": true + }, + { + "name": "pageKey", + "description": "String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results.", + "schema": { + "type": "string" + }, + "in": "query" + }, + { + "name": "pageSize", + "description": "Number of owners to be returned per page.", + "schema": { + "type": "integer" + }, + "in": "query" + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "owners": { + "type": "array", + "description": "List of all addresses that own the given NFT.", + "items": { + "type": "string" + } + } + } + } + } + } + } + }, + "operationId": "getOwnersForToken" + } + }, + "/v2/{apiKey}/getOwnersForCollection": { + "get": { + "summary": "getOwnersForCollection", + "description": "Gets all owners for a given NFT contract.", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0x1f02bf9dde7c79137a08b2dd4fc964bfd2499734" + }, + "required": true + }, + { + "name": "withTokenBalances", + "description": "Boolean - If set to `true` the query will include the token balances per token id for each owner. `false` by default.", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "description": "String - used for collections with >50,000 owners. `pageKey` field can be passed back as request parameter to get the next page of results.", + "name": "pageKey", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "description": "List of all addresses that own the given NFT.", + "items": { + "type": "string" + } + } + } + } + } + }, + "operationId": "getOwnersForCollection" + } + }, + "/v2/{apiKey}/getSpamContracts": { + "get": { + "summary": "getSpamContracts", + "description": "Returns a list of all spam contracts marked by Alchemy.", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "servers": [ + { + "url": "https://{network}.g.alchemy.com/nft", + "variables": { + "network": { + "enum": [ + "eth-mainnet", + "polygon-mainnet" + ], + "default": "eth-mainnet" + } + } + } + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "Object that has list of contract addresses", + "properties": { + "contractAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "description": "A list of contract addresses earmarked as spam by Alchemy." + } + } + } + } + } + } + }, + "operationId": "getSpamContracts" + } + }, + "/v2/{apiKey}/isSpamContract": { + "get": { + "summary": "isSpamContract", + "description": "Returns whether a contract is marked as spam or not by Alchemy.", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "servers": [ + { + "url": "https://{network}.g.alchemy.com/nft", + "variables": { + "network": { + "enum": [ + "eth-mainnet", + "polygon-mainnet" + ], + "default": "eth-mainnet" + } + } + } + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0x495f947276749ce646f68ac8c248420045cb7b5e" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "boolean", + "description": "True - if the queried contract is marked as spam.\nFalse - if the queried contract is considered valid or if the contract hasn't been evaluated by us yet.\n" + } + } + } + } + }, + "operationId": "isSpamContract" + } + }, + "/v2/{apiKey}/isAirdrop": { + "get": { + "summary": "isAirdrop", + "description": "Returns whether a token is marked as an airdrop or not. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address.", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + }, + { + "name": "tokenId", + "description": "String - The ID of the token. Can be in hex or decimal format.", + "in": "query", + "schema": { + "type": "string", + "default": "44" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "boolean", + "description": "True - if the queried token is marked as an airdrop.\nFalse - if the queried token is not marked as an airdrop.\n" + } + } + } + } + }, + "operationId": "isAirdrop" + } + }, + "/v2/{apiKey}/invalidateContract": { + "get": { + "summary": "invalidateContract", + "description": "Marks all cached tokens for the particular contract as stale. So the next time the endpoint is queried it fetches live data instead of fetching from cache.", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "True - if the queried contract is marked as spam.\nFalse - if the queried contract is considered valid.\n", + "properties": { + "success": { + "type": "string", + "description": "True if the contract was invalidated.\nFalse - if it wasn't.\n" + }, + "numTokensInvalidated": { + "type": "number", + "description": "The number of tokens that were invalidated as a result of running this query." + } + } + } + } + } + } + }, + "operationId": "invalidateContract" + } + }, + "/v2/{apiKey}/getFloorPrice": { + "get": { + "summary": "getFloorPrice", + "description": "Returns the floor prices of a NFT collection by marketplace.", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "servers": [ + { + "url": "https://{network}.g.alchemy.com/nft", + "variables": { + "network": { + "enum": [ + "eth-mainnet" + ], + "default": "eth-mainnet" + } + } + } + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "nftMarketplace": { + "type": "object", + "description": "Name of the NFT marketplace where the collection is listed. Current marketplaces supported - OpenSea, LooksRare", + "properties": { + "floorPrice": { + "type": "number", + "description": "Number - The floor price of the collection on the given marketplace." + }, + "priceCurrency": { + "type": "string", + "description": "String - The currency in which the floor price is denominated. Typically, denominated in ETH", + "enum": [ + "ETH" + ] + }, + "collectionUrl": { + "type": "string", + "description": "String - Link to the collection on the given marketplace." + }, + "retrievedAt": { + "type": "string", + "description": "String - UTC timestamp of when the floor price was retrieved from the marketplace." + }, + "error": { + "type": "string", + "description": "String - Returns an error if there was an error fetching floor prices from the given marketplace." + } + } + } + } + } + } + } + } + }, + "operationId": "getFloorPrice" + } + }, + "/v2/{apiKey}/computeRarity": { + "get": { + "summary": "computeRarity", + "description": "Computes the rarity of each attribute of an NFT.", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "servers": [ + { + "url": "https://{network}.g.alchemy.com/nft", + "variables": { + "network": { + "enum": [ + "eth-mainnet", + "polygon-mainnet" + ], + "default": "eth-mainnet" + } + } + } + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + }, + { + "name": "tokenId", + "description": "String - The ID of the token. Can be in hex or decimal format.", + "in": "query", + "schema": { + "type": "string", + "default": "44" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "Object containing the rarity info of the collection", + "properties": { + "rarities": { + "type": "array", + "description": "NFT attributes and their associated prevalence.", + "items": { + "type": "object", + "properties": { + "trait_type": { + "type": "string", + "description": "Name of the trait category, i.e. Hat, Color, Face, etc." + }, + "value": { + "type": "string", + "description": "Value for the trait, i.e. White Cap, Blue, Angry, etc." + }, + "prevalence": { + "type": "number", + "description": "Floating point value from 0 to 1 representing the prevalence of this value for this trait type." + } + } + } + } + } + } + } + } + } + }, + "operationId": "computeRarity" + } + }, + "/v2/{apiKey}/searchContractMetadata": { + "get": { + "summary": "searchContractMetadata", + "description": "Search for a keyword across metadata of all ERC-721 and ERC-1155 smart contracts", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "servers": [ + { + "url": "https://{network}.g.alchemy.com/nft", + "variables": { + "network": { + "enum": [ + "eth-mainnet" + ], + "default": "eth-mainnet" + } + } + } + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "query", + "description": "String - The search string that you want to search for in contract metadata", + "in": "query", + "schema": { + "type": "string", + "default": "bored" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "Returns the list of NFT contracts where the metadata has one or more keywords from the search string.", + "content": { + "application/json": { + "schema": { + "type": "array", + "description": "List of contracts where the metadata contains one or more keywords from the search string.", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "contractMetadata": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "opensea": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + } + } + } + } + } + } + } + } + } + }, + "operationId": "searchContractMetadata" + } + }, + "/v2/{apiKey}/summarizeNFTAttributes": { + "get": { + "summary": "summarizeNFTAttributes", + "description": "Generate a summary of attribute prevalence for an NFT collection.", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "servers": [ + { + "url": "https://{network}.g.alchemy.com/nft", + "variables": { + "network": { + "enum": [ + "eth-mainnet", + "polygon-mainnet" + ], + "default": "eth-mainnet" + } + } + } + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "Prevalence counts for each attribute within a collection.", + "properties": { + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "summary": { + "type": "object", + "description": "Object mapping trait types to the prevalence of each trait within that type." + }, + "contractAddress": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + } + } + } + } + } + } + }, + "operationId": "summarizeNFTAttributes" + } + }, + "/v2/{apiKey}/isHolderOfCollection": { + "get": { + "summary": "isHolderOfCollection", + "description": "Checks whether a wallet holds a NFT in a given collection", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "wallet", + "description": "String - Address for NFT owner (can be in ENS format for Eth Mainnet).", + "schema": { + "type": "string", + "default": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + }, + "in": "query", + "required": true + }, + { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "Data related to a wallet's ownership of any token in an NFT collection.", + "properties": { + "isHolderOfCollection": { + "type": "boolean", + "description": "Whether the given wallet owns any token in the given NFT collection." + } + } + } + } + } + } + }, + "operationId": "isHolderOfCollection" + } + }, + "/v2/{apiKey}/getNFTSales": { + "get": { + "summary": "getNFTSales", + "description": "Gets NFT sales that have happened through on-chain marketplaces", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "servers": [ + { + "url": "https://{network}.g.alchemy.com/nft", + "variables": { + "network": { + "enum": [ + "eth-mainnet", + "polygon-mainnet", + "opt-mainnet" + ], + "default": "eth-mainnet" + } + } + } + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "fromBlock", + "description": "String - The block number to start fetching NFT sales data from. Allowed values are decimal and hex integers, and \"latest\". Defaults to \"0\".", + "in": "query", + "schema": { + "type": "string", + "default": "0" + } + }, + { + "name": "toBlock", + "description": "String - The block number to start fetching NFT sales data from. Allowed values are decimal and hex integers, and \"latest\". Defaults to \"latest\".", + "in": "query", + "schema": { + "type": "string", + "default": "latest" + } + }, + { + "name": "order", + "description": "Enum - Whether to return the results ascending from startBlock or descending from startBlock. Defaults to descending (false).", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc" + } + }, + { + "name": "marketplace", + "description": "Enum - The name of the NFT marketplace to filter sales by. The endpoint currently supports \"seaport\", \"wyvern\", \"looksrare\", \"x2y2\", \"blur\", and \"cryptopunks\". Defaults to returning sales from all supported marketplaces.", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "seaport", + "looksrare", + "x2y2", + "wyvern", + "blur", + "cryptopunks" + ] + }, + "required": false + }, + { + "description": "String - The contract address of a NFT collection to filter sales by. Defaults to returning all NFT contracts.", + "name": "contractAddress", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "description": "String - The token ID of an NFT within the collection specified by contractAddress to filter sales by. Defaults to returning all token IDs.", + "name": "tokenId", + "in": "query", + "schema": { + "type": "string", + "default": "44" + }, + "required": false + }, + { + "name": "buyerAddress", + "description": "String - The address of the NFT buyer to filter sales by. Defaults to returning sales involving any buyer.", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "sellerAddress", + "description": "String - The address of the NFT seller to filter sales by. Defaults to returning sales involving any seller.", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "taker", + "description": "Enum - Filter by whether the buyer or seller was the taker in the NFT trade. Allowed filter values are \"BUYER\" and \"SELLER\". Defaults to returning both buyer and seller taker trades.", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "BUYER", + "SELLER" + ] + }, + "required": false + }, + { + "description": "Integer - The maximum number of NFT sales to return. Maximum and default values are 1000.", + "name": "limit", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "pageKey", + "description": "String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results.", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "nftSales": { + "description": "List of NFT sales that match the query", + "type": "array", + "items": { + "type": "object", + "properties": { + "marketplace": { + "type": "string", + "description": "String - The marketplace the sale took place on." + }, + "contractAddress": { + "type": "string", + "description": "String - The contract address of the collection the NFT belongs to." + }, + "tokenId": { + "type": "string", + "description": "String - The decimal token ID of the NFT being sold." + }, + "quantity": { + "type": "string", + "description": "Integer - The number of tokens sold in the sale as a decimal integer string." + }, + "buyerAddress": { + "type": "string", + "description": "String - The address of the buyer in the NFT sale." + }, + "sellerAddress": { + "type": "string", + "description": "String - The address of the seller in the NFT sale." + }, + "taker": { + "type": "string", + "description": "String - Whether the price taker in the trade was the buyer or the seller.", + "enum": [ + "BUYER", + "SELLER" + ] + }, + "sellerFee": { + "type": "object", + "description": "The payment from buyer to the seller", + "properties": { + "amount": { + "type": "string", + "description": "String - The amount of the payment from the buyer to seller as a decimal integer string." + }, + "symbol": { + "type": "string", + "description": "String - The symbol of the token used for the payment." + }, + "decimals": { + "type": "integer", + "description": "Integer - The number of decimals of the token used for the payment." + } + } + }, + "protocolFee": { + "type": "object", + "description": "The payment from buyer to the NFT marketplace protocol", + "properties": { + "amount": { + "type": "string", + "description": "String - The amount of the payment to the marketplace as a decimal integer string." + }, + "symbol": { + "type": "string", + "description": "String - The symbol of the token used for the payment." + }, + "decimals": { + "type": "integer", + "description": "Integer - The number of decimals of the token used for the payment." + } + } + }, + "royaltyFee": { + "type": "object", + "description": "The payment from buyer to the royalty address of the NFT collection", + "properties": { + "amount": { + "type": "string", + "description": "String - The amount of the payment to the royalty collector as a decimal integer string." + }, + "symbol": { + "type": "string", + "description": "String - The symbol of the token used for the payment." + }, + "decimals": { + "type": "integer", + "description": "Integer - The number of decimals of the token used for the payment." + } + } + }, + "blockNumber": { + "type": "integer", + "description": "Integer - The block number the NFT sale took place in." + }, + "logIndex": { + "type": "integer", + "description": "Integer - The log number of the sale event emitted within the block." + }, + "bundleIndex": { + "type": "integer", + "description": "Integer - The index of the token within the bundle of NFTs sold in the sale." + }, + "transactionHash": { + "type": "string", + "description": "String - The transaction hash of the transaction containing the sale." + } + } + } + }, + "pageKey": { + "type": "string", + "description": "String - The page key to use to fetch the next page of results. Returns null if there are no more results." + } + } + }, + "examples": { + "nftSales_response": { + "summary": "Response (with pagination)", + "value": { + "nftSales": [ + { + "marketplace": "seaport", + "contractAddress": "0x49cf6f5d44e70224e2e23fdcdd2c053f30ada28b", + "tokenId": "13749", + "quantity": "1", + "buyerAddress": "0x78f6c2458b53d0735208992c693bb2b2dafebb52", + "sellerAddress": "0x558a18f94cabdea4e47c5965384f457d8e870419", + "taker": "BUYER", + "sellerFee": { + "amount": "11100000000000000000", + "symbol": "ETH", + "decimals": 18 + }, + "protocolFee": { + "amount": "300000000000000000", + "symbol": "ETH", + "decimals": 18 + }, + "royaltyFee": { + "amount": "600000000000000000", + "symbol": "ETH", + "decimals": 18 + }, + "blockNumber": 15000002, + "logIndex": 130, + "bundleIndex": 0, + "transactionHash": "0xecfa1b29c9016bd2556fde637c6b48484eeb14f273af54c49317e3856ab7cb16" + }, + { + "marketplace": "looksrare", + "contractAddress": "0x34d85c9cdeb23fa97cb08333b511ac86e1c4e258", + "tokenId": "75417", + "quantity": "1", + "buyerAddress": "0xb3aa9923489bc2bfec323bf05346acd4afbc92a0", + "sellerAddress": "0x206ccba024c236dced07c35b4e9eb0bade7ef166", + "taker": "BUYER", + "sellerFee": { + "amount": "2222700000000000000", + "symbol": "WETH", + "decimals": 18 + }, + "protocolFee": { + "amount": "47800000000000000", + "symbol": "WETH", + "decimals": 18 + }, + "royaltyFee": { + "amount": "119500000000000000", + "symbol": "WETH", + "decimals": 18 + }, + "blockNumber": 15000002, + "logIndex": 197, + "bundleIndex": 0, + "transactionHash": "0x4c23163e4f855e143e573776bc6129bee370dff6ce760e71553fc93201b292e2" + } + ], + "pageKey": "MTUwMDAwNzgsODcsMA", + "validAt": { + "blockNumber": 17091500, + "blockHash": "0x2a34a65c4e0cd7fdf187d6a497214ad2bee255d2d3501868a6b8c09b4d1261bd", + "blockTimestamp": "2023-04-21T01:25:59Z" + } + } + } + } + } + } + } + }, + "operationId": "getNFTSales" + } + }, + "/v2/{apiKey}/getContractsForOwner": { + "get": { + "summary": "getContractsForOwner", + "description": "Gets all NFT contracts held by an owner address.", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "owner", + "description": "String - Address for NFT owner (can be in ENS format for Eth Mainnet).", + "schema": { + "type": "string", + "default": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + }, + "in": "query", + "required": true + }, + { + "name": "pageKey", + "description": "String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results.", + "schema": { + "type": "string" + }, + "in": "query" + }, + { + "name": "pageSize", + "description": "Number of NFTs to be returned per page. Defaults to 100. Max is 100.", + "schema": { + "type": "integer", + "default": 100 + }, + "in": "query" + }, + { + "name": "withMetadata", + "description": "Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "schema": { + "type": "boolean", + "default": true + }, + "in": "query" + }, + { + "name": "includeFilters[]", + "description": "Array of filters (as ENUMS) that will be applied to the query. Only NFTs that match one or more of these filters will be included in the response. May not be used in conjunction with excludeFilters[]. Filter Options:\n - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**.\n - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only.\n - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts)", + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "in": "query" + }, + { + "name": "excludeFilters[]", + "description": "Array of filters (as ENUMS) that will be applied to the query. NFTs that match one or more of these filters will be excluded from the response. May not be used in conjunction with includeFilters[]. Filter Options:\n - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**.\n - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only.\n - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts)", + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "in": "query" + }, + { + "name": "orderBy", + "description": "Enum - ordering scheme to use for ordering NFTs in the response. If unspecified, NFTs will be ordered by contract address and token ID.\n - transferTime: NFTs will be ordered by the time they were transferred into the wallet, with newest NFTs first. Note: This ordering is supported on Ethereum Mainnet, Optimism Mainnet, Polygon Mainnet, Base Mainnet, Arbitrum One, Polygon Amoy, Base Sepolia, Arbitrum Sepolia, Ethereum Sepolia, and Optimism Sepolia.", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "transferTime" + ] + }, + "required": false + }, + { + "name": "spamConfidenceLevel", + "description": "Enum - the confidence level at which to filter spam at.\n\nConfidence Levels:\n - VERY_HIGH\n - HIGH\n - MEDIUM\n - LOW\n\nThe confidence level set means that any spam that is at that confidence level or higher will be filtered out. For example, if the confidence level is HIGH, contracts that we have HIGH or VERY_HIGH confidence in being spam will be filtered out from the response. \nDefaults to VERY_HIGH for Ethereum Mainnet and MEDIUM for Matic Mainnet.\n\n**Please note that this filter is only available on paid tiers. Upgrade your account [here](https://dashboard.alchemy.com/settings/billing/).**", + "schema": { + "type": "string", + "enum": [ + "VERY_HIGH", + "HIGH", + "MEDIUM", + "LOW" + ] + }, + "in": "query", + "required": false + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "contracts": { + "type": "array", + "items": { + "type": "object", + "description": "The object that represents a smart contract and has all data corresponding to that contract", + "properties": { + "address": { + "description": "Address of the held contract", + "type": "string" + }, + "totalBalance": { + "type": "number", + "description": "Sum of NFT balances across all token IDs held by the owner. For non-fungible tokens this will be equal to the `numDistinctTokensOwned`, but it may be higher if the user holds some fungible ERC1155 tokens." + }, + "numDistinctTokensOwned": { + "type": "number", + "description": "Number of distinct token IDs held by the owner. For non-fungible tokens this will be equal to the `totalBalance`, but it may be lower if the user holds some fungible ERC1155 tokens." + }, + "isSpam": { + "type": "boolean" + }, + "tokenId": { + "description": "One of the tokens from this contract held by the owner.", + "type": "string" + }, + "name": { + "description": "The name of the contract, i.e. \"Bored Ape Yacht Club\".", + "type": "string" + }, + "title": { + "description": "The title of the token held by the owner i.e. \"Something #22\".", + "type": "string" + }, + "symbol": { + "description": "The symbol of the contract, i.e. BAYC.", + "type": "string" + }, + "tokenType": { + "description": "The NFT standard used by the contract, i.e. ERC721 or ERC1155.", + "type": "string" + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "media": { + "type": "array", + "items": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + }, + "thumbnail": { + "type": "string", + "description": "URL for a resized thumbnail of the NFT media asset." + }, + "format": { + "type": "string", + "description": "The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets." + }, + "bytes": { + "type": "integer", + "description": "The size of the media asset in bytes." + } + } + } + }, + "opensea": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + } + } + } + }, + "pageKey": { + "type": "string" + }, + "totalCount": { + "type": "string", + "description": "String - Total number of NFT contracts held by the given address returned in this page." + } + } + }, + "examples": { + "withoutMetadata": { + "summary": "Response (withMetadata = false)", + "value": { + "contracts": [ + { + "address": "0x000386e3f7559d9b6a2f5c46b4ad1a9587d59dc3", + "totalBalance": 912, + "numDistinctTokensOwned": 80, + "isSpam": true, + "tokenId": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "address": "0x0015f391949f25c3211063104ad4afc99210f85c", + "totalBalance": 17, + "numDistinctTokensOwned": 6, + "isSpam": true, + "tokenId": "0x0000000000000000000000000000000000000000000000000000000000000002" + }, + { + "address": "0x005b92d71a934dbe48e985b6469881cf4b0308fc", + "totalBalance": 1, + "numDistinctTokensOwned": 1, + "isSpam": true, + "tokenId": "0x0000000000000000000000000000000000000000000000000000000000000003" + } + ], + "totalCount": 2120, + "pageKey": "20ef9df5-0d81-42e5-b741-140f595a407b" + } + }, + "withMetadata": { + "summary": "Response (withMetadata = true)", + "value": { + "contracts": [ + { + "address": "0x1C310c2fbB0D9755A6b918F990bC8D3504f2c684", + "name": "The Wonderful Husl Founder Cards", + "symbol": "The Wonderful Husl Founder Cards", + "totalSupply": null, + "tokenType": "ERC1155", + "contractDeployer": "0x0bdD0AEC835F92a465290cdd57b27FBd00376F53", + "deployedBlockNumber": 15664554, + "openSeaMetadata": { + "floorPrice": null, + "collectionName": "The Wonderful Husl Founder Cards", + "safelistRequestStatus": "not_requested", + "imageUrl": "https://i.seadn.io/gcs/files/754e38769c80c9d6188444dddb10ec80.png?w=500&auto=format", + "description": "[Husl](https://www.huslnft.xyz) is building the bridge between business and NFTs. Husl Founders are the driven, the passionate and the focused members of the community ready to change their future. Owning a Founders Card gets you exclusive perks, early access to business management, and discounts on managed services for your business as NFT. [Learn More](https://www.huslnft.xyz)", + "externalUrl": "https://www.huslnft.xyz", + "twitterUsername": null, + "discordUrl": null, + "lastIngestedAt": "2023-03-20T01:36:19.000Z" + }, + "totalBalance": "1", + "numDistinctTokensOwned": "1", + "isSpam": true, + "displayNft": { + "tokenId": "233", + "name": null + }, + "image": { + "cachedUrl": "https://nft-cdn.alchemy.com/eth-mainnet/d08d0d0fac8edf36ea09eae34b332814", + "thumbnailUrl": "https://res.cloudinary.com/alchemyapi/image/upload/thumbnailv2/eth-mainnet/d08d0d0fac8edf36ea09eae34b332814", + "pngUrl": "https://res.cloudinary.com/alchemyapi/image/upload/convert-png/eth-mainnet/d08d0d0fac8edf36ea09eae34b332814", + "contentType": "video/mp4", + "size": 36190302, + "originalUrl": "https://ipfs.io/ipfs/QmX2mM8r33W7KUBQSWXFAKNC2t654EXmWiX9vkrfrEaEnS" + } + } + ], + "totalCount": 2120, + "pageKey": "03949322-9b2c-4fdd-aab6-1369e29fa5b2" + } + } + } + } + } + } + }, + "operationId": "getContractsForOwner" + } + }, + "/v2/{apiKey}/reportSpam": { + "get": { + "summary": "reportSpam", + "description": "Report a particular address to our APIs if you think it is spam", + "tags": [ + "NFT API V2 Methods (Older Version)" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + { + "name": "address", + "description": "String - The address to check for spam status.", + "in": "query", + "schema": { + "type": "string", + "default": "0x495f947276749ce646f68ac8c248420045cb7b5e" + }, + "required": true + }, + { + "name": "isSpam", + "description": "Boolean - Whether the address is spam.", + "in": "query", + "schema": { + "type": "boolean", + "default": true + }, + "required": true + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "string", + "description": "String - \"Address was successfully reported as spam\" if calling the API was successful. " + } + } + } + } + }, + "operationId": "reportSpam" + } + } + }, + "components": { + "parameters": { + "apiKey": { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + }, + "owner": { + "name": "owner", + "description": "String - Address for NFT owner (can be in ENS format for Eth Mainnet).", + "schema": { + "type": "string", + "default": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + }, + "in": "query", + "required": true + }, + "wallet": { + "name": "wallet", + "description": "String - Wallet address to check for contract ownership.", + "schema": { + "type": "string", + "default": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + }, + "in": "query", + "required": true + }, + "pageKey": { + "name": "pageKey", + "description": "String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results.", + "schema": { + "type": "string" + }, + "in": "query" + }, + "pageSize": { + "name": "pageSize", + "description": "Number of NFTs to be returned per page. Defaults to 100. Max is 100.", + "schema": { + "type": "integer", + "default": 100 + }, + "in": "query" + }, + "getOwnersForTokenPageSize": { + "name": "pageSize", + "description": "Number of owners to be returned per page.", + "schema": { + "type": "integer" + }, + "in": "query" + }, + "contractAddresses": { + "name": "contractAddresses[]", + "description": "Array of contract addresses to filter the responses with. Max limit 45 contracts.", + "schema": { + "type": "array", + "items": { + "type": "string" + } + }, + "in": "query" + }, + "withMetadata": { + "name": "withMetadata", + "description": "Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "schema": { + "type": "boolean", + "default": true + }, + "in": "query" + }, + "excludeFilters": { + "name": "excludeFilters[]", + "description": "Array of filters (as ENUMS) that will be applied to the query. NFTs that match one or more of these filters will be excluded from the response. May not be used in conjunction with includeFilters[]. Filter Options:\n - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**.\n - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only.\n - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts)", + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "in": "query" + }, + "address": { + "name": "address", + "description": "String - any valid blockchain address for NFT collections, contracts, mints, etc.", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": false + }, + "addressRequired": { + "name": "address", + "description": "String - any valid blockchain address for NFT collections, contracts, mints, etc.", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + }, + "includeFilters": { + "name": "includeFilters[]", + "description": "Array of filters (as ENUMS) that will be applied to the query. Only NFTs that match one or more of these filters will be included in the response. May not be used in conjunction with excludeFilters[]. Filter Options:\n - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**.\n - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only.\n - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts)", + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "in": "query" + }, + "spamConfidenceLevel": { + "name": "spamConfidenceLevel", + "description": "Enum - the confidence level at which to filter spam at.\n\nConfidence Levels:\n - VERY_HIGH\n - HIGH\n - MEDIUM\n - LOW\n\nThe confidence level set means that any spam that is at that confidence level or higher will be filtered out. For example, if the confidence level is HIGH, contracts that we have HIGH or VERY_HIGH confidence in being spam will be filtered out from the response. \nDefaults to VERY_HIGH for Ethereum Mainnet and MEDIUM for Matic Mainnet.\n\n**Please note that this filter is only available on paid tiers. Upgrade your account [here](https://dashboard.alchemy.com/settings/billing/).**", + "schema": { + "type": "string", + "enum": [ + "VERY_HIGH", + "HIGH", + "MEDIUM", + "LOW" + ] + }, + "in": "query", + "required": false + }, + "collectionSlug": { + "name": "collectionSlug", + "description": "String - OpenSea slug for the NFT collection.", + "in": "query", + "schema": { + "type": "string", + "default": "boredapeyachtclub" + }, + "required": false + }, + "collectionSlugRequired": { + "name": "collectionSlug", + "description": "String - OpenSea slug for the NFT collection.", + "in": "query", + "schema": { + "type": "string", + "default": "boredapeyachtclub" + }, + "required": true + }, + "contractAddressRequired": { + "name": "contractAddress", + "description": "String - Contract address for the NFT contract (ERC721 and ERC1155 supported).", + "in": "query", + "schema": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "required": true + }, + "tokenId": { + "name": "tokenId", + "description": "String - The ID of the token. Can be in hex or decimal format.", + "in": "query", + "schema": { + "type": "string", + "default": "44" + }, + "required": true + }, + "tokenIdV3": { + "name": "tokenId", + "description": "String - The ID of the token in decimal format.", + "in": "query", + "schema": { + "type": "string", + "default": "44" + }, + "required": true + }, + "tokenIdForNFTSales": { + "name": "tokenId", + "description": "String - The ID of the token. Can be in hex or decimal format.", + "in": "query", + "schema": { + "type": "string", + "default": "44" + }, + "required": false + }, + "tokenType": { + "name": "tokenType", + "description": "String - 'ERC721' or 'ERC1155'; specifies type of token to query for. API requests will perform faster if this is specified.", + "in": "query", + "schema": { + "type": "string" + } + }, + "startToken": { + "name": "startToken", + "description": "String - A tokenID offset used for pagination. Can be a hex string, or a decimal. Users can specify the offset themselves to start from a custom offset, or to fetch multiple token ranges in parallel.", + "in": "query", + "schema": { + "type": "string" + } + }, + "limit": { + "name": "limit", + "description": "Integer - Sets the total number of NFTs returned in the response. Defaults to 100.", + "in": "query", + "schema": { + "type": "integer" + } + }, + "tokenUriTimeoutInMs": { + "name": "tokenUriTimeoutInMs", + "description": "No set timeout by default - When metadata is requested, this parameter is the timeout (in milliseconds) for the website hosting the metadata to respond. If you want to _only_ access the cache and not live fetch any metadata for cache misses then set this value to 0.", + "in": "query", + "schema": { + "type": "integer" + } + }, + "withTokenBalances": { + "name": "withTokenBalances", + "description": "Boolean - If set to `true` the query will include the token balances per token id for each owner. `false` by default.", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + "refreshCache": { + "name": "refreshCache", + "description": "Defaults to false for faster response times. If true will refresh metadata for given token. If false will check the cache and use it or refresh if cache doesn't exist.", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + "block": { + "name": "block", + "description": "String - The point in time or block number (in hex or decimal) to fetch collection ownership information for.", + "in": "query", + "schema": { + "type": "string" + } + }, + "fromBlock": { + "name": "fromBlock", + "description": "String - The block number to start fetching NFT sales data from. Allowed values are decimal and hex integers, and \"latest\". Defaults to \"0\".", + "in": "query", + "schema": { + "type": "string", + "default": "0" + } + }, + "order": { + "name": "order", + "description": "Enum - Whether to return the results ascending from startBlock or descending from startBlock. Defaults to descending (false).", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc" + } + }, + "orderBy": { + "name": "orderBy", + "description": "Enum - ordering scheme to use for ordering NFTs in the response. If unspecified, NFTs will be ordered by contract address and token ID.\n - transferTime: NFTs will be ordered by the time they were transferred into the wallet, with newest NFTs first. Note: This ordering is supported on Ethereum Mainnet, Optimism Mainnet, Polygon Mainnet, Base Mainnet, Arbitrum One, Polygon Amoy, Base Sepolia, Arbitrum Sepolia, Ethereum Sepolia, and Optimism Sepolia.", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "transferTime" + ] + }, + "required": false + }, + "marketplace": { + "name": "marketplace", + "description": "Enum - The name of the NFT marketplace to filter sales by. The endpoint currently supports \"seaport\", \"wyvern\", \"looksrare\", \"x2y2\", \"blur\", and \"cryptopunks\". Defaults to returning sales from all supported marketplaces.", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "seaport", + "looksrare", + "x2y2", + "wyvern", + "blur", + "cryptopunks" + ] + }, + "required": false + }, + "buyerAddress": { + "name": "buyerAddress", + "description": "String - The address of the NFT buyer to filter sales by. Defaults to returning sales involving any buyer.", + "in": "query", + "schema": { + "type": "string" + } + }, + "sellerAddress": { + "name": "sellerAddress", + "description": "String - The address of the NFT seller to filter sales by. Defaults to returning sales involving any seller.", + "in": "query", + "schema": { + "type": "string" + } + }, + "taker": { + "name": "taker", + "description": "Enum - Filter by whether the buyer or seller was the taker in the NFT trade. Allowed filter values are \"BUYER\" and \"SELLER\". Defaults to returning both buyer and seller taker trades.", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "BUYER", + "SELLER" + ] + }, + "required": false + }, + "query": { + "name": "query", + "description": "String - The search string that you want to search for in contract metadata", + "in": "query", + "schema": { + "type": "string", + "default": "bored" + }, + "required": true + } + }, + "schemas": { + "rawv3": { + "type": "object", + "description": "Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract", + "properties": { + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "metadata": { + "type": "object", + "description": "Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually.", + "properties": { + "image": { + "type": "string", + "description": "String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces." + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms)" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trait_type": { + "type": "string" + } + } + }, + "description": "Object - Traits/attributes/characteristics for each NFT asset." + } + } + }, + "error": { + "type": "string", + "description": "String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT." + } + } + }, + "id": { + "type": "object", + "properties": { + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenMetadata": { + "type": "object", + "properties": { + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + } + } + } + } + }, + "idV3": { + "type": "object", + "properties": { + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenMetadata": { + "type": "object", + "properties": { + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + } + } + } + } + }, + "tokenUri": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + } + } + }, + "metadata": { + "type": "object", + "description": "Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually.", + "properties": { + "image": { + "type": "string", + "description": "String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces." + }, + "external_url": { + "type": "string", + "description": "String - The image URL that appears alongside the asset image on NFT platforms." + }, + "background_color": { + "type": "string", + "description": "String - Background color of the NFT item. Usually must be defined as a six-character hexadecimal." + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms)" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trait_type": { + "type": "string" + } + } + }, + "description": "Object - Traits/attributes/characteristics for each NFT asset." + }, + "media": { + "type": "array", + "items": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + }, + "thumbnail": { + "type": "string", + "description": "URL for a resized thumbnail of the NFT media asset." + }, + "format": { + "type": "string", + "description": "The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets." + }, + "bytes": { + "type": "integer", + "description": "The size of the media asset in bytes." + } + } + } + } + } + }, + "ownedContract": { + "type": "object", + "description": "The object that represents a smart contract and has all data corresponding to that contract", + "properties": { + "address": { + "description": "Address of the held contract", + "type": "string" + }, + "totalBalance": { + "type": "number", + "description": "Sum of NFT balances across all token IDs held by the owner. For non-fungible tokens this will be equal to the `numDistinctTokensOwned`, but it may be higher if the user holds some fungible ERC1155 tokens." + }, + "numDistinctTokensOwned": { + "type": "number", + "description": "Number of distinct token IDs held by the owner. For non-fungible tokens this will be equal to the `totalBalance`, but it may be lower if the user holds some fungible ERC1155 tokens." + }, + "isSpam": { + "type": "boolean" + }, + "tokenId": { + "description": "One of the tokens from this contract held by the owner.", + "type": "string" + }, + "name": { + "description": "The name of the contract, i.e. \"Bored Ape Yacht Club\".", + "type": "string" + }, + "title": { + "description": "The title of the token held by the owner i.e. \"Something #22\".", + "type": "string" + }, + "symbol": { + "description": "The symbol of the contract, i.e. BAYC.", + "type": "string" + }, + "tokenType": { + "description": "The NFT standard used by the contract, i.e. ERC721 or ERC1155.", + "type": "string" + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "media": { + "type": "array", + "items": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + }, + "thumbnail": { + "type": "string", + "description": "URL for a resized thumbnail of the NFT media asset." + }, + "format": { + "type": "string", + "description": "The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets." + }, + "bytes": { + "type": "integer", + "description": "The size of the media asset in bytes." + } + } + } + }, + "opensea": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + } + } + }, + "ownedContractv3": { + "type": "object", + "description": "The object that represents a smart contract and has all data corresponding to that contract", + "properties": { + "address": { + "type": "string", + "default": "0xe785E82358879F061BC3dcAC6f0444462D4b5330" + }, + "name": { + "description": "The name of the contract, i.e. \"Bored Ape Yacht Club\".", + "type": "string" + }, + "symbol": { + "description": "The symbol of the contract, i.e. BAYC.", + "type": "string" + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string" + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + }, + "totalBalance": { + "type": "number", + "description": "Sum of NFT balances across all token IDs held by the owner. For non-fungible tokens this will be equal to the `numDistinctTokensOwned`, but it may be higher if the user holds some fungible ERC1155 tokens." + }, + "numDistinctTokensOwned": { + "type": "number", + "description": "Number of distinct token IDs held by the owner. For non-fungible tokens this will be equal to the `totalBalance`, but it may be lower if the user holds some fungible ERC1155 tokens." + }, + "isSpam": { + "type": "boolean", + "description": "`True` if the contract is detected as spam contract. `False` if it is not spam or has not been evaluated by our system yet" + }, + "displayNft": { + "type": "object", + "description": "Details of the display NFT for this contract. This NFT and its image can be used to represent the contract when displaying info about it.", + "properties": { + "tokenId": { + "description": "One of the tokens from this contract held by the owner.", + "type": "string" + }, + "name": { + "description": "The title of the token held by the owner i.e. \"Something #22\".", + "type": "string" + } + } + }, + "image": { + "type": "object", + "description": "Details of the image corresponding to this contract", + "properties": { + "cachedUrl": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "thumbnailUrl": { + "type": "string", + "description": "The Url that has the thumbnail version of the NFT" + }, + "pngUrl": { + "type": "string", + "description": "The Url that has the NFT image in png" + }, + "contentType": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "size": { + "type": "integer", + "description": "The size of the media asset in bytes." + }, + "originalUrl": { + "type": "string", + "description": "The original Url of the image coming straight from the smart contract" + } + } + } + } + }, + "ownedCollectionv3": { + "type": "object", + "description": "Metadata for an NFT collection held by an owner address. Includes general metadata about the collection, as well as information specific to the owner such as the total balance and the token ID of a random NFT for display purposes.", + "properties": { + "name": { + "description": "The name of the collection, i.e. \"Bored Ape Yacht Club\".", + "type": "string" + }, + "slug": { + "description": "The human-readable string used to identify the collection on OpenSea.", + "type": "string" + }, + "floorPrice": { + "type": "object", + "description": "Floor price data for the collection", + "properties": { + "marketplace": { + "description": "The marketplace the floor price is on", + "type": "string" + }, + "floorPrice": { + "description": "Floor price of the collection on the marketplace", + "type": "number" + }, + "priceCurrency": { + "description": "The currency of the floor price", + "type": "string" + } + } + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "contract": { + "type": "object", + "description": "Contract-level data for a collection, such as contract type, name, and symbol.", + "properties": { + "address": { + "description": "Address of the contract", + "type": "string" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + } + } + }, + "totalBalance": { + "type": "number", + "description": "Sum of NFT balances across all token IDs held by the owner. For non-fungible tokens this will be equal to the `numDistinctTokensOwned`, but it may be higher if the user holds some fungible ERC1155 tokens." + }, + "numDistinctTokensOwned": { + "type": "number", + "description": "Number of distinct token IDs held by the owner. For non-fungible tokens this will be equal to the `totalBalance`, but it may be lower if the user holds some fungible ERC1155 tokens." + }, + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "displayNft": { + "type": "object", + "description": "Details of the display NFT for this contract. This NFT and its image can be used to represent the contract when displaying info about it.", + "properties": { + "tokenId": { + "description": "One of the tokens from this contract held by the owner.", + "type": "string" + }, + "name": { + "description": "The title of the token held by the owner i.e. \"Something #22\".", + "type": "string" + } + } + }, + "image": { + "type": "object", + "description": "Details of the image corresponding to this contract", + "properties": { + "cachedUrl": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "thumbnailUrl": { + "type": "string", + "description": "The Url that has the thumbnail version of the NFT" + }, + "pngUrl": { + "type": "string", + "description": "The Url that has the NFT image in png" + }, + "contentType": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "size": { + "type": "integer", + "description": "The size of the media asset in bytes." + }, + "originalUrl": { + "type": "string", + "description": "The original Url of the image coming straight from the smart contract" + } + } + } + } + }, + "ownedCollectionContract": { + "type": "object", + "description": "Contract-level data for a collection, such as contract type, name, and symbol.", + "properties": { + "address": { + "description": "Address of the contract", + "type": "string" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + } + } + }, + "media": { + "type": "array", + "items": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + }, + "thumbnail": { + "type": "string", + "description": "URL for a resized thumbnail of the NFT media asset." + }, + "format": { + "type": "string", + "description": "The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets." + }, + "bytes": { + "type": "integer", + "description": "The size of the media asset in bytes." + } + } + } + }, + "ownedNFT": { + "type": "object", + "description": "The object that represents an NFT and has all data corresponding to that NFT", + "properties": { + "contract": { + "description": "Object - Contract for returned NFT", + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "String - Address of NFT contract." + } + } + }, + "id": { + "type": "object", + "properties": { + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenMetadata": { + "type": "object", + "properties": { + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + } + } + } + } + }, + "balance": { + "type": "string", + "description": "String - Token balance" + }, + "title": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Brief human-readable description" + }, + "tokenUri": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + } + } + }, + "media": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + }, + "thumbnail": { + "type": "string", + "description": "URL for a resized thumbnail of the NFT media asset." + }, + "format": { + "type": "string", + "description": "The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets." + }, + "bytes": { + "type": "integer", + "description": "The size of the media asset in bytes." + } + } + }, + "metadata": { + "type": "object", + "description": "Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually.", + "properties": { + "image": { + "type": "string", + "description": "String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces." + }, + "external_url": { + "type": "string", + "description": "String - The image URL that appears alongside the asset image on NFT platforms." + }, + "background_color": { + "type": "string", + "description": "String - Background color of the NFT item. Usually must be defined as a six-character hexadecimal." + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms)" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trait_type": { + "type": "string" + } + } + }, + "description": "Object - Traits/attributes/characteristics for each NFT asset." + }, + "media": { + "type": "array", + "items": { + "type": "object", + "properties": { + "raw": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "gateway": { + "type": "string", + "description": "String - Public gateway uri for the raw uri above." + }, + "thumbnail": { + "type": "string", + "description": "URL for a resized thumbnail of the NFT media asset." + }, + "format": { + "type": "string", + "description": "The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets." + }, + "bytes": { + "type": "integer", + "description": "The size of the media asset in bytes." + } + } + } + } + } + }, + "timeLastUpdated": { + "type": "string", + "description": "String - ISO timestamp of the last cache refresh for the information returned in the metadata field." + }, + "error": { + "type": "string", + "description": "String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT." + }, + "contractMetadata": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "opensea": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + } + } + }, + "spamInfo": { + "type": "object", + "description": "Information about whether and why a contract was marked as spam.", + "properties": { + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "spamClassifications": { + "description": "List of reasons why a contract was classified as spam. **Only available on paid tiers.**", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "acquiredAt": { + "type": "object", + "description": "Only present if the request specified `orderBy=transferTime`.", + "properties": { + "blockTimestamp": { + "type": "string", + "description": "Block timestamp of the block where the NFT was most recently acquired." + }, + "blockNumber": { + "type": "string", + "description": "Block number of the block where the NFT was most recently acquired." + } + } + } + } + }, + "ownedNFTv3": { + "type": "object", + "description": "The object that represents an NFT and has all data corresponding to that NFT", + "properties": { + "contract": { + "type": "object", + "description": "The contract object that has details of a contract", + "properties": { + "address": { + "description": "Address of the held contract", + "type": "string" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + }, + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "spamClassifications": { + "description": "List of reasons why a contract was classified as spam. **Only available on paid tiers.**", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenType": { + "type": "string" + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Brief human-readable description" + }, + "image": { + "type": "object", + "description": "Details of the image corresponding to this contract", + "properties": { + "cachedUrl": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "thumbnailUrl": { + "type": "string", + "description": "The Url that has the thumbnail version of the NFT" + }, + "pngUrl": { + "type": "string", + "description": "The Url that has the NFT image in png" + }, + "contentType": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "size": { + "type": "integer", + "description": "The size of the media asset in bytes." + }, + "originalUrl": { + "type": "string", + "description": "The original Url of the image coming straight from the smart contract" + } + } + }, + "raw": { + "type": "object", + "description": "Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract", + "properties": { + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "metadata": { + "type": "object", + "description": "Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually.", + "properties": { + "image": { + "type": "string", + "description": "String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces." + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms)" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trait_type": { + "type": "string" + } + } + }, + "description": "Object - Traits/attributes/characteristics for each NFT asset." + } + } + }, + "error": { + "type": "string", + "description": "String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT." + } + } + }, + "collection": { + "type": "object", + "description": "The collection object that has details of a collection", + "properties": { + "name": { + "type": "string", + "description": "String - Collection name" + }, + "slug": { + "type": "string", + "description": "String - OpenSea collection slug" + }, + "externalUrl": { + "type": "string", + "description": "String - URL for the external site of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "String - Banner image URL for the collection" + } + } + }, + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "timeLastUpdated": { + "type": "string", + "description": "String - ISO timestamp of the last cache refresh for the information returned in the metadata field." + }, + "acquiredAt": { + "type": "object", + "description": "Only present if the request specified `orderBy=transferTime`.", + "properties": { + "blockTimestamp": { + "type": "string", + "description": "Block timestamp of the block where the NFT was most recently acquired." + }, + "blockNumber": { + "type": "string", + "description": "Block number of the block where the NFT was most recently acquired." + } + } + }, + "animation": { + "type": "object", + "properties": { + "cachedUrl": { + "type": "string" + }, + "contentType": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "orginalUrl": { + "type": "string" + } + } + }, + "mint": { + "type": "object", + "properties": { + "mintAddress": { + "type": "string", + "description": "Address that minted the NFT" + }, + "blockNumber": { + "type": "integer", + "description": "Block number when the NFT was minted" + }, + "timestamp": { + "type": "string", + "description": "Timestamp when the NFT was minted" + }, + "transactionHash": { + "type": "string", + "description": "Transaction hash of the mint transaction" + } + } + }, + "owners": { + "type": "array", + "description": "List of all addresses that own the given NFT.", + "items": { + "type": "string" + } + } + } + }, + "contractMetadata": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "opensea": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + } + } + }, + "contractMetadatav3": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "String - Contract address for the queried NFT collection" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + } + } + }, + "collectionMetadatav3": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "String - Name of the queried NFT Collection" + }, + "slug": { + "description": "The human-readable string used to identify the collection on OpenSea.", + "type": "string" + }, + "floorPrice": { + "type": "object", + "description": "Floor price data for the collection", + "properties": { + "marketplace": { + "description": "The marketplace the floor price is on", + "type": "string" + }, + "floorPrice": { + "description": "Floor price of the collection on the marketplace", + "type": "number" + }, + "priceCurrency": { + "description": "The currency of the floor price", + "type": "string" + } + } + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + } + } + }, + "contractv3": { + "type": "object", + "description": "The contract object that has details of a contract", + "properties": { + "address": { + "description": "Address of the held contract", + "type": "string" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + }, + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "spamClassifications": { + "description": "List of reasons why a contract was classified as spam. **Only available on paid tiers.**", + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } +} diff --git a/packages/api-codegen/specs/portfolio.json b/packages/api-codegen/specs/portfolio.json new file mode 100644 index 0000000000..8a9d094209 --- /dev/null +++ b/packages/api-codegen/specs/portfolio.json @@ -0,0 +1,3210 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "🧠 Data", + "version": "1.0" + }, + "servers": [ + { + "url": "https://api.g.alchemy.com/data/v1" + } + ], + "paths": { + "/{apiKey}/assets/tokens/by-address": { + "post": { + "summary": "Tokens By Wallet", + "description": "Fetches fungible tokens (native, ERC-20 and SPL) for multiple wallet addresses and networks. Returns a list of tokens with balances, prices, and metadata for each wallet/network combination. This endpoint is supported on Ethereum, Solana, and 30+ EVM chains. See the full list of supported networks [here](https://dashboard.alchemy.com/chains).\n", + "tags": [ + "Portfolio API Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "addresses": { + "type": "array", + "description": "Array of wallet addresses and the networks to query them on. Maximum 2 addresses and maximum 5 networks per address.\n", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "Wallet address.", + "example": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152", + "default": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152" + }, + "networks": { + "type": "array", + "default": [ + "eth-mainnet", + "base-mainnet", + "matic-mainnet" + ], + "items": { + "type": "string", + "default": "eth-mainnet" + }, + "description": "Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains)" + } + }, + "required": [ + "address", + "networks" + ] + } + }, + "withMetadata": { + "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "type": "boolean", + "default": true + }, + "withPrices": { + "description": "Boolean - if set to `true`, returns token prices. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "type": "boolean", + "default": true + }, + "includeNativeTokens": { + "type": "boolean", + "description": "Whether to include each chain's native token in the response (e.g. ETH on Ethereum). The native token will have a null contract address.", + "example": true, + "default": true + }, + "includeErc20Tokens": { + "description": "Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "type": "boolean", + "default": true + } + }, + "required": [ + "addresses" + ] + }, + "example": { + "addresses": [ + { + "address": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152", + "networks": [ + "eth-mainnet", + "base-mainnet", + "matic-mainnet" + ] + } + ], + "withMetadata": true, + "withPrices": true, + "includeNativeTokens": true, + "includeErc20Tokens": false + } + } + } + }, + "responses": { + "200": { + "description": "Successful response!", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "description": "List of tokens by address, with prices and metadata.", + "properties": { + "tokens": { + "type": "array", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "Wallet address." + }, + "network": { + "type": "string", + "description": "Network identifier." + }, + "tokenAddress": { + "type": "string", + "description": "Token address." + }, + "tokenBalance": { + "type": "string", + "description": "Balance of that particular token." + }, + "tokenMetadata": { + "type": "object", + "properties": { + "decimals": { + "type": "integer", + "description": "Number of decimals the token uses" + }, + "logo": { + "type": "string", + "description": "URL of the token's logo image" + }, + "name": { + "type": "string", + "description": "Token's name" + }, + "symbol": { + "type": "string", + "description": "Token's symbol" + } + } + }, + "tokenPrices": { + "type": "array", + "description": "List of price information.", + "items": { + "type": "object", + "properties": { + "currency": { + "type": "string", + "example": "usd" + }, + "value": { + "type": "string", + "example": "4608.2208671202" + }, + "lastUpdatedAt": { + "type": "string", + "format": "date-time", + "example": "2025-08-26T20:17:27Z" + } + }, + "required": [ + "currency", + "value", + "lastUpdatedAt" + ] + } + }, + "error": { + "type": [ + "string", + "null" + ], + "description": "Error message if applicable." + } + }, + "required": [ + "network", + "address", + "tokenAddress", + "tokenBalance" + ] + } + }, + "pageKey": { + "type": "string" + } + } + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "description": "Bad Request: Invalid input (e.g., malformed JSON).", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Detailed error message." + } + }, + "required": [ + "message" + ], + "description": "Error details." + } + }, + "required": [ + "error" + ] + } + } + } + }, + "429": { + "description": "Too Many Requests: Rate limit exceeded.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Detailed error message." + } + }, + "required": [ + "message" + ], + "description": "Error details." + } + }, + "required": [ + "error" + ] + } + } + } + } + }, + "operationId": "get-tokens-by-address" + } + }, + "/{apiKey}/assets/tokens/balances/by-address": { + "post": { + "summary": "Token Balances By Wallet", + "description": "Fetches fungible tokens (native, ERC-20, and SPL) for multiple wallet addresses and networks. Returns a list of tokens with balances for each wallet/network combination. This endpoint is supported on Ethereum, Solana, and 30+ EVM chains. See the full list of supported networks [here](https://dashboard.alchemy.com/chains)\n", + "tags": [ + "Portfolio API Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "addresses": { + "type": "array", + "description": "Array of address and networks pairs (limit 3 pairs, max 20 networks). Networks should match network enums.\n", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "Wallet address.", + "example": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152", + "default": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152" + }, + "networks": { + "type": "array", + "default": [ + "eth-mainnet", + "base-mainnet", + "matic-mainnet" + ], + "items": { + "type": "string", + "default": "eth-mainnet" + }, + "description": "Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains)" + } + }, + "required": [ + "address", + "networks" + ] + } + }, + "includeNativeTokens": { + "type": "boolean", + "description": "Whether to include each chain's native token in the response (e.g. ETH on Ethereum). The native token will have a null contract address.", + "example": true, + "default": true + }, + "includeErc20Tokens": { + "description": "Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "type": "boolean", + "default": true + } + }, + "required": [ + "addresses" + ] + }, + "example": { + "addresses": [ + { + "address": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152", + "networks": [ + "eth-mainnet", + "base-mainnet", + "matic-mainnet" + ] + } + ], + "includeNativeTokens": true, + "includeErc20Tokens": false + } + } + } + }, + "responses": { + "200": { + "description": "Successful response!", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "tokens": { + "type": "array", + "description": "List of token balances by address.", + "items": { + "type": "object", + "properties": { + "network": { + "type": "string", + "description": "Network identifier." + }, + "address": { + "type": "string", + "description": "Wallet address." + }, + "tokenAddress": { + "type": "string", + "description": "Token address." + }, + "tokenBalance": { + "type": "string", + "description": "Balance of that particular token." + } + }, + "required": [ + "network", + "address", + "tokenAddress", + "tokenBalance" + ] + } + }, + "pageKey": { + "type": "string" + } + } + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "description": "Bad Request: Invalid input (e.g., malformed JSON).", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Detailed error message." + } + }, + "required": [ + "message" + ], + "description": "Error details." + } + }, + "required": [ + "error" + ] + } + } + } + }, + "429": { + "description": "Too Many Requests: Rate limit exceeded.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Detailed error message." + } + }, + "required": [ + "message" + ], + "description": "Error details." + } + }, + "required": [ + "error" + ] + } + } + } + } + }, + "operationId": "get-token-balances-by-address" + } + }, + "/{apiKey}/assets/nfts/by-address": { + "post": { + "summary": "NFTs By Wallet", + "description": "Fetches NFTs for multiple wallet addresses and networks. Returns a list of NFTs and metadata for each wallet/network combination. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains).\n", + "tags": [ + "Portfolio API Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "type": "object", + "properties": { + "addresses": { + "type": "array", + "description": "Array of address and networks pairs (limit 2 pairs, max 15 networks each). Networks should match network enums.\n", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "Wallet address.", + "example": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152", + "default": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152" + }, + "networks": { + "type": "array", + "default": [ + "eth-mainnet", + "base-mainnet", + "matic-mainnet" + ], + "items": { + "type": "string", + "enum": [ + "eth-mainnet", + "eth-sepolia", + "eth-holesky", + "avax-mainnet", + "avax-fuji", + "zksync-mainnet", + "opt-mainnet", + "polygon-mainnet", + "polygon-amoy", + "arb-mainnet", + "arb-sepolia", + "blast-mainnet", + "blast-sepolia", + "base-mainnet", + "base-sepolia", + "soneium-mainnet", + "soneium-minato", + "scroll-mainnet", + "scroll-sepolia", + "shape-mainnet", + "shape-sepolia", + "lens-mainnet", + "lens-sepolia", + "starknet-mainnet", + "starknet-sepolia", + "rootstock-mainnet", + "rootstock-testnet", + "linea-mainnet", + "linea-sepolia", + "settlus-septestnet", + "abstract-mainnet", + "abstract-testnet", + "apechain-mainnet" + ], + "default": "eth-mainnet" + }, + "description": "Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains)" + }, + "excludeFilters": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "includeFilters": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "spamConfidenceLevel": { + "type": "string", + "enum": [ + "VERY_HIGH", + "HIGH", + "MEDIUM", + "LOW" + ] + } + }, + "required": [ + "address", + "networks" + ] + } + }, + "withMetadata": { + "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "type": "boolean", + "default": true + }, + "pageKey": { + "type": "string" + }, + "pageSize": { + "type": "integer", + "default": 100 + } + }, + "required": [ + "addresses" + ] + }, + { + "type": "object", + "properties": { + "orderBy": { + "type": "string", + "enum": [ + "transferTime" + ], + "description": "Field to order results by" + }, + "sortOrder": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "description": "Sort order for results" + } + } + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "Successful response!", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "description": "List of nfts by address with appropriate metadata.", + "properties": { + "ownedNfts": { + "type": "array", + "items": { + "type": "object", + "description": "The object that represents an NFT and has all data corresponding to that NFT", + "properties": { + "network": { + "type": "string", + "description": "Network identifier." + }, + "address": { + "type": "string", + "description": "Wallet address." + }, + "contract": { + "type": "object", + "description": "The contract object that has details of a contract", + "properties": { + "address": { + "description": "Address of the held contract", + "type": "string" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + }, + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "spamClassifications": { + "description": "List of reasons why a contract was classified as spam. **Only available on paid tiers.**", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenType": { + "type": "string" + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Brief human-readable description" + }, + "image": { + "type": "object", + "description": "Details of the image corresponding to this contract", + "properties": { + "cachedUrl": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "thumbnailUrl": { + "type": "string", + "description": "The Url that has the thumbnail version of the NFT" + }, + "pngUrl": { + "type": "string", + "description": "The Url that has the NFT image in png" + }, + "contentType": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "size": { + "type": "integer", + "description": "The size of the media asset in bytes." + }, + "originalUrl": { + "type": "string", + "description": "The original Url of the image coming straight from the smart contract" + } + } + }, + "raw": { + "type": "object", + "description": "Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract", + "properties": { + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "metadata": { + "type": "object", + "description": "Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually.", + "properties": { + "image": { + "type": "string", + "description": "String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces." + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms)" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trait_type": { + "type": "string" + } + } + }, + "description": "Object - Traits/attributes/characteristics for each NFT asset." + } + } + }, + "error": { + "type": "string", + "description": "String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT." + } + } + }, + "collection": { + "type": "object", + "description": "The collection object that has details of a collection", + "properties": { + "name": { + "type": "string", + "description": "String - Collection name" + }, + "slug": { + "type": "string", + "description": "String - OpenSea collection slug" + }, + "externalUrl": { + "type": "string", + "description": "String - URL for the external site of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "String - Banner image URL for the collection" + } + } + }, + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "timeLastUpdated": { + "type": "string", + "description": "String - ISO timestamp of the last cache refresh for the information returned in the metadata field." + }, + "acquiredAt": { + "type": "object", + "description": "Only present if the request specified `orderBy=transferTime`.", + "properties": { + "blockTimestamp": { + "type": "string", + "description": "Block timestamp of the block where the NFT was most recently acquired." + }, + "blockNumber": { + "type": "string", + "description": "Block number of the block where the NFT was most recently acquired." + } + } + } + } + } + }, + "totalCount": { + "type": "integer", + "description": "Integer - Total number of NFTs (distinct `tokenIds`) owned by the given address." + }, + "pageKey": { + "type": "string" + } + } + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "description": "Bad Request: Invalid input (e.g., malformed JSON).", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Detailed error message." + } + }, + "required": [ + "message" + ], + "description": "Error details." + } + }, + "required": [ + "error" + ] + } + } + } + }, + "429": { + "description": "Too Many Requests: Rate limit exceeded.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Detailed error message." + } + }, + "required": [ + "message" + ], + "description": "Error details." + } + }, + "required": [ + "error" + ] + } + } + } + } + }, + "operationId": "get-nfts-by-address" + } + }, + "/{apiKey}/assets/nfts/contracts/by-address": { + "post": { + "summary": "NFT Collections By Wallet", + "description": "Fetches NFT collections (contracts) for multiple wallet addresses and networks. Returns a list of collections and metadata for each wallet/network combination. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains).\n", + "tags": [ + "Portfolio API Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "type": "object", + "properties": { + "addresses": { + "type": "array", + "description": "Array of address and networks pairs (limit 2 pairs, max 15 networks each). Networks should match network enums.\n", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "Wallet address.", + "example": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152", + "default": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152" + }, + "networks": { + "type": "array", + "default": [ + "eth-mainnet", + "base-mainnet", + "matic-mainnet" + ], + "items": { + "type": "string", + "enum": [ + "eth-mainnet", + "eth-sepolia", + "eth-holesky", + "avax-mainnet", + "avax-fuji", + "zksync-mainnet", + "opt-mainnet", + "polygon-mainnet", + "polygon-amoy", + "arb-mainnet", + "arb-sepolia", + "blast-mainnet", + "blast-sepolia", + "base-mainnet", + "base-sepolia", + "soneium-mainnet", + "soneium-minato", + "scroll-mainnet", + "scroll-sepolia", + "shape-mainnet", + "shape-sepolia", + "lens-mainnet", + "lens-sepolia", + "starknet-mainnet", + "starknet-sepolia", + "rootstock-mainnet", + "rootstock-testnet", + "linea-mainnet", + "linea-sepolia", + "settlus-septestnet", + "abstract-mainnet", + "abstract-testnet", + "apechain-mainnet" + ], + "default": "eth-mainnet" + }, + "description": "Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains)" + }, + "excludeFilters": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "includeFilters": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "spamConfidenceLevel": { + "type": "string", + "enum": [ + "VERY_HIGH", + "HIGH", + "MEDIUM", + "LOW" + ] + } + }, + "required": [ + "address", + "networks" + ] + } + }, + "withMetadata": { + "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "type": "boolean", + "default": true + }, + "pageKey": { + "type": "string" + }, + "pageSize": { + "type": "integer", + "default": 100 + } + }, + "required": [ + "addresses" + ] + }, + { + "type": "object", + "properties": { + "orderBy": { + "type": "string", + "enum": [ + "transferTime" + ], + "description": "Field to order results by" + }, + "sortOrder": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "description": "Sort order for results" + } + } + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "Successful response!", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "description": "List of nft collections.", + "properties": { + "contracts": { + "type": "array", + "items": { + "type": "object", + "description": "The object that represents an NFT collection", + "properties": { + "network": { + "type": "string", + "description": "Network identifier." + }, + "address": { + "type": "string", + "description": "Wallet address." + }, + "contract": { + "type": "object", + "description": "The contract object that has details of a contract", + "properties": { + "address": { + "description": "Address of the held contract", + "type": "string" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + }, + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "spamClassifications": { + "description": "List of reasons why a contract was classified as spam. **Only available on paid tiers.**", + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + }, + "totalCount": { + "type": "integer", + "description": "Integer - Total number of NFTs (distinct `tokenIds`) owned by the given address." + }, + "pageKey": { + "type": "string" + } + } + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "description": "Bad Request: Invalid input (e.g., malformed JSON).", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Detailed error message." + } + }, + "required": [ + "message" + ], + "description": "Error details." + } + }, + "required": [ + "error" + ] + } + } + } + }, + "429": { + "description": "Too Many Requests: Rate limit exceeded.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Detailed error message." + } + }, + "required": [ + "message" + ], + "description": "Error details." + } + }, + "required": [ + "error" + ] + } + } + } + } + }, + "operationId": "get-nft-contracts-by-address" + } + } + }, + "components": { + "schemas": { + "ByAddressRequest": { + "type": "object", + "properties": { + "addresses": { + "type": "array", + "description": "Array of wallet addresses and the networks to query them on. Maximum 2 addresses and maximum 5 networks per address.\n", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "Wallet address.", + "example": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152", + "default": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152" + }, + "networks": { + "type": "array", + "default": [ + "eth-mainnet", + "base-mainnet", + "matic-mainnet" + ], + "items": { + "type": "string", + "default": "eth-mainnet" + }, + "description": "Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains)" + } + }, + "required": [ + "address", + "networks" + ] + } + } + }, + "required": [ + "addresses" + ] + }, + "ByAddressRequestWith1AddressAnd2Networks": { + "type": "object", + "properties": { + "addresses": { + "type": "array", + "description": "Array of address and networks pairs (limit 1 pairs, max 2 networks). Networks should match network enums.\n", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "Wallet address.", + "example": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152", + "default": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152" + }, + "networks": { + "type": "array", + "default": [ + "eth-mainnet", + "base-mainnet" + ], + "items": { + "type": "string", + "default": "eth-mainnet" + }, + "description": "(In BETA and only accepts ETH & BASE mainnets). Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains)" + } + }, + "required": [ + "address", + "networks" + ] + } + }, + "before": { + "type": "string", + "description": "The cursor that points to the previous set of results." + }, + "after": { + "type": "string", + "description": "The cursor that points to the end of the current set of results." + }, + "limit": { + "type": "integer", + "description": "Sets the maximum number of items per page (Max: 50)", + "default": 25 + }, + "pageKey": { + "type": "string" + } + }, + "required": [ + "addresses" + ] + }, + "ByAddressRequestWith3PairsAnd20Networks": { + "type": "object", + "properties": { + "addresses": { + "type": "array", + "description": "Array of address and networks pairs (limit 3 pairs, max 20 networks). Networks should match network enums.\n", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "Wallet address.", + "example": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152", + "default": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152" + }, + "networks": { + "type": "array", + "default": [ + "eth-mainnet", + "base-mainnet", + "matic-mainnet" + ], + "items": { + "type": "string", + "default": "eth-mainnet" + }, + "description": "Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains)" + } + }, + "required": [ + "address", + "networks" + ] + } + }, + "includeNativeTokens": { + "type": "boolean", + "description": "Whether to include each chain's native token in the response (e.g. ETH on Ethereum). The native token will have a null contract address.", + "example": true, + "default": true + }, + "includeErc20Tokens": { + "description": "Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "type": "boolean", + "default": true + } + }, + "required": [ + "addresses" + ] + }, + "ByAddressRequestWithOptions": { + "type": "object", + "properties": { + "addresses": { + "type": "array", + "description": "Array of wallet addresses and the networks to query them on. Maximum 2 addresses and maximum 5 networks per address.\n", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "Wallet address.", + "example": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152", + "default": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152" + }, + "networks": { + "type": "array", + "default": [ + "eth-mainnet", + "base-mainnet", + "matic-mainnet" + ], + "items": { + "type": "string", + "default": "eth-mainnet" + }, + "description": "Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains)" + } + }, + "required": [ + "address", + "networks" + ] + } + }, + "withMetadata": { + "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "type": "boolean", + "default": true + }, + "withPrices": { + "description": "Boolean - if set to `true`, returns token prices. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "type": "boolean", + "default": true + }, + "includeNativeTokens": { + "type": "boolean", + "description": "Whether to include each chain's native token in the response (e.g. ETH on Ethereum). The native token will have a null contract address.", + "example": true, + "default": true + }, + "includeErc20Tokens": { + "description": "Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "type": "boolean", + "default": true + } + }, + "required": [ + "addresses" + ] + }, + "ByAddressRequestWithNFTOptionsAndPaging": { + "type": "object", + "properties": { + "addresses": { + "type": "array", + "description": "Array of address and networks pairs (limit 2 pairs, max 15 networks each). Networks should match network enums.\n", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "Wallet address.", + "example": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152", + "default": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152" + }, + "networks": { + "type": "array", + "default": [ + "eth-mainnet", + "base-mainnet", + "matic-mainnet" + ], + "items": { + "type": "string", + "enum": [ + "eth-mainnet", + "eth-sepolia", + "eth-holesky", + "avax-mainnet", + "avax-fuji", + "zksync-mainnet", + "opt-mainnet", + "polygon-mainnet", + "polygon-amoy", + "arb-mainnet", + "arb-sepolia", + "blast-mainnet", + "blast-sepolia", + "base-mainnet", + "base-sepolia", + "soneium-mainnet", + "soneium-minato", + "scroll-mainnet", + "scroll-sepolia", + "shape-mainnet", + "shape-sepolia", + "lens-mainnet", + "lens-sepolia", + "starknet-mainnet", + "starknet-sepolia", + "rootstock-mainnet", + "rootstock-testnet", + "linea-mainnet", + "linea-sepolia", + "settlus-septestnet", + "abstract-mainnet", + "abstract-testnet", + "apechain-mainnet" + ], + "default": "eth-mainnet" + }, + "description": "Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains)" + }, + "excludeFilters": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "includeFilters": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "spamConfidenceLevel": { + "type": "string", + "enum": [ + "VERY_HIGH", + "HIGH", + "MEDIUM", + "LOW" + ] + } + }, + "required": [ + "address", + "networks" + ] + } + }, + "withMetadata": { + "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "type": "boolean", + "default": true + }, + "pageKey": { + "type": "string" + }, + "pageSize": { + "type": "integer", + "default": 100 + } + }, + "required": [ + "addresses" + ] + }, + "ByAddressRequestWithNFTOptions": { + "type": "object", + "properties": { + "addresses": { + "type": "array", + "description": "Array of wallet addresses and the networks to query them on. Maximum 2 addresses and maximum 5 networks per address.\n", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "Wallet address.", + "example": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152", + "default": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152" + }, + "networks": { + "type": "array", + "default": [ + "eth-mainnet", + "base-mainnet", + "matic-mainnet" + ], + "items": { + "type": "string", + "default": "eth-mainnet" + }, + "description": "Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains)" + } + }, + "required": [ + "address", + "networks" + ] + } + }, + "withMetadata": { + "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "type": "boolean", + "default": true + } + }, + "required": [ + "addresses" + ] + }, + "AddressItemForNFTOwnership": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "Wallet address.", + "example": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152", + "default": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152" + }, + "networks": { + "type": "array", + "default": [ + "eth-mainnet", + "base-mainnet", + "matic-mainnet" + ], + "items": { + "type": "string", + "enum": [ + "eth-mainnet", + "eth-sepolia", + "eth-holesky", + "avax-mainnet", + "avax-fuji", + "zksync-mainnet", + "opt-mainnet", + "polygon-mainnet", + "polygon-amoy", + "arb-mainnet", + "arb-sepolia", + "blast-mainnet", + "blast-sepolia", + "base-mainnet", + "base-sepolia", + "soneium-mainnet", + "soneium-minato", + "scroll-mainnet", + "scroll-sepolia", + "shape-mainnet", + "shape-sepolia", + "lens-mainnet", + "lens-sepolia", + "starknet-mainnet", + "starknet-sepolia", + "rootstock-mainnet", + "rootstock-testnet", + "linea-mainnet", + "linea-sepolia", + "settlus-septestnet", + "abstract-mainnet", + "abstract-testnet", + "apechain-mainnet" + ], + "default": "eth-mainnet" + }, + "description": "Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains)" + }, + "excludeFilters": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "includeFilters": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "SPAM", + "AIRDROPS" + ], + "default": "SPAM" + } + }, + "spamConfidenceLevel": { + "type": "string", + "enum": [ + "VERY_HIGH", + "HIGH", + "MEDIUM", + "LOW" + ] + } + }, + "required": [ + "address", + "networks" + ] + }, + "TokensResponse": { + "type": "object", + "properties": { + "data": { + "type": "object", + "description": "List of tokens by address, with prices and metadata.", + "properties": { + "tokens": { + "type": "array", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string", + "description": "Wallet address." + }, + "network": { + "type": "string", + "description": "Network identifier." + }, + "tokenAddress": { + "type": "string", + "description": "Token address." + }, + "tokenBalance": { + "type": "string", + "description": "Balance of that particular token." + }, + "tokenMetadata": { + "type": "object", + "properties": { + "decimals": { + "type": "integer", + "description": "Number of decimals the token uses" + }, + "logo": { + "type": "string", + "description": "URL of the token's logo image" + }, + "name": { + "type": "string", + "description": "Token's name" + }, + "symbol": { + "type": "string", + "description": "Token's symbol" + } + } + }, + "tokenPrices": { + "type": "array", + "description": "List of price information.", + "items": { + "type": "object", + "properties": { + "currency": { + "type": "string", + "example": "usd" + }, + "value": { + "type": "string", + "example": "4608.2208671202" + }, + "lastUpdatedAt": { + "type": "string", + "format": "date-time", + "example": "2025-08-26T20:17:27Z" + } + }, + "required": [ + "currency", + "value", + "lastUpdatedAt" + ] + } + }, + "error": { + "type": [ + "string", + "null" + ], + "description": "Error message if applicable." + } + }, + "required": [ + "network", + "address", + "tokenAddress", + "tokenBalance" + ] + } + }, + "pageKey": { + "type": "string" + } + } + } + }, + "required": [ + "data" + ] + }, + "TokenBalancesResponse": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "tokens": { + "type": "array", + "description": "List of token balances by address.", + "items": { + "type": "object", + "properties": { + "network": { + "type": "string", + "description": "Network identifier." + }, + "address": { + "type": "string", + "description": "Wallet address." + }, + "tokenAddress": { + "type": "string", + "description": "Token address." + }, + "tokenBalance": { + "type": "string", + "description": "Balance of that particular token." + } + }, + "required": [ + "network", + "address", + "tokenAddress", + "tokenBalance" + ] + } + }, + "pageKey": { + "type": "string" + } + } + } + }, + "required": [ + "data" + ] + }, + "NFTByOwnerResponse": { + "type": "object", + "properties": { + "data": { + "type": "object", + "description": "List of nfts by address with appropriate metadata.", + "properties": { + "ownedNfts": { + "type": "array", + "items": { + "type": "object", + "description": "The object that represents an NFT and has all data corresponding to that NFT", + "properties": { + "network": { + "type": "string", + "description": "Network identifier." + }, + "address": { + "type": "string", + "description": "Wallet address." + }, + "contract": { + "type": "object", + "description": "The contract object that has details of a contract", + "properties": { + "address": { + "description": "Address of the held contract", + "type": "string" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + }, + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "spamClassifications": { + "description": "List of reasons why a contract was classified as spam. **Only available on paid tiers.**", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenType": { + "type": "string" + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Brief human-readable description" + }, + "image": { + "type": "object", + "description": "Details of the image corresponding to this contract", + "properties": { + "cachedUrl": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "thumbnailUrl": { + "type": "string", + "description": "The Url that has the thumbnail version of the NFT" + }, + "pngUrl": { + "type": "string", + "description": "The Url that has the NFT image in png" + }, + "contentType": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "size": { + "type": "integer", + "description": "The size of the media asset in bytes." + }, + "originalUrl": { + "type": "string", + "description": "The original Url of the image coming straight from the smart contract" + } + } + }, + "raw": { + "type": "object", + "description": "Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract", + "properties": { + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "metadata": { + "type": "object", + "description": "Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually.", + "properties": { + "image": { + "type": "string", + "description": "String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces." + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms)" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trait_type": { + "type": "string" + } + } + }, + "description": "Object - Traits/attributes/characteristics for each NFT asset." + } + } + }, + "error": { + "type": "string", + "description": "String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT." + } + } + }, + "collection": { + "type": "object", + "description": "The collection object that has details of a collection", + "properties": { + "name": { + "type": "string", + "description": "String - Collection name" + }, + "slug": { + "type": "string", + "description": "String - OpenSea collection slug" + }, + "externalUrl": { + "type": "string", + "description": "String - URL for the external site of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "String - Banner image URL for the collection" + } + } + }, + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "timeLastUpdated": { + "type": "string", + "description": "String - ISO timestamp of the last cache refresh for the information returned in the metadata field." + }, + "acquiredAt": { + "type": "object", + "description": "Only present if the request specified `orderBy=transferTime`.", + "properties": { + "blockTimestamp": { + "type": "string", + "description": "Block timestamp of the block where the NFT was most recently acquired." + }, + "blockNumber": { + "type": "string", + "description": "Block number of the block where the NFT was most recently acquired." + } + } + } + } + } + }, + "totalCount": { + "type": "integer", + "description": "Integer - Total number of NFTs (distinct `tokenIds`) owned by the given address." + }, + "pageKey": { + "type": "string" + } + } + } + }, + "required": [ + "data" + ] + }, + "NFTCollectionsByOwnerResponse": { + "type": "object", + "properties": { + "data": { + "type": "object", + "description": "List of nft collections.", + "properties": { + "contracts": { + "type": "array", + "items": { + "type": "object", + "description": "The object that represents an NFT collection", + "properties": { + "network": { + "type": "string", + "description": "Network identifier." + }, + "address": { + "type": "string", + "description": "Wallet address." + }, + "contract": { + "type": "object", + "description": "The contract object that has details of a contract", + "properties": { + "address": { + "description": "Address of the held contract", + "type": "string" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + }, + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "spamClassifications": { + "description": "List of reasons why a contract was classified as spam. **Only available on paid tiers.**", + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + }, + "totalCount": { + "type": "integer", + "description": "Integer - Total number of NFTs (distinct `tokenIds`) owned by the given address." + }, + "pageKey": { + "type": "string" + } + } + } + }, + "required": [ + "data" + ] + }, + "NFTResponseItem": { + "type": "object", + "description": "The object that represents an NFT and has all data corresponding to that NFT", + "properties": { + "network": { + "type": "string", + "description": "Network identifier." + }, + "address": { + "type": "string", + "description": "Wallet address." + }, + "contract": { + "type": "object", + "description": "The contract object that has details of a contract", + "properties": { + "address": { + "description": "Address of the held contract", + "type": "string" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + }, + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "spamClassifications": { + "description": "List of reasons why a contract was classified as spam. **Only available on paid tiers.**", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "tokenId": { + "type": "string", + "default": "44" + }, + "tokenType": { + "type": "string" + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Brief human-readable description" + }, + "image": { + "type": "object", + "description": "Details of the image corresponding to this contract", + "properties": { + "cachedUrl": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "thumbnailUrl": { + "type": "string", + "description": "The Url that has the thumbnail version of the NFT" + }, + "pngUrl": { + "type": "string", + "description": "The Url that has the NFT image in png" + }, + "contentType": { + "type": "string", + "description": "The Url of the image stored in Alchemy cache" + }, + "size": { + "type": "integer", + "description": "The size of the media asset in bytes." + }, + "originalUrl": { + "type": "string", + "description": "The original Url of the image coming straight from the smart contract" + } + } + }, + "raw": { + "type": "object", + "description": "Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract", + "properties": { + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "metadata": { + "type": "object", + "description": "Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually.", + "properties": { + "image": { + "type": "string", + "description": "String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces." + }, + "name": { + "type": "string", + "description": "String - Name of the NFT asset." + }, + "description": { + "type": "string", + "description": "String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms)" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trait_type": { + "type": "string" + } + } + }, + "description": "Object - Traits/attributes/characteristics for each NFT asset." + } + } + }, + "error": { + "type": "string", + "description": "String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT." + } + } + }, + "collection": { + "type": "object", + "description": "The collection object that has details of a collection", + "properties": { + "name": { + "type": "string", + "description": "String - Collection name" + }, + "slug": { + "type": "string", + "description": "String - OpenSea collection slug" + }, + "externalUrl": { + "type": "string", + "description": "String - URL for the external site of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "String - Banner image URL for the collection" + } + } + }, + "tokenUri": { + "type": "string", + "description": "String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated." + }, + "timeLastUpdated": { + "type": "string", + "description": "String - ISO timestamp of the last cache refresh for the information returned in the metadata field." + }, + "acquiredAt": { + "type": "object", + "description": "Only present if the request specified `orderBy=transferTime`.", + "properties": { + "blockTimestamp": { + "type": "string", + "description": "Block timestamp of the block where the NFT was most recently acquired." + }, + "blockNumber": { + "type": "string", + "description": "Block number of the block where the NFT was most recently acquired." + } + } + } + } + }, + "NFTCollectionResponseItem": { + "type": "object", + "description": "The object that represents an NFT collection", + "properties": { + "network": { + "type": "string", + "description": "Network identifier." + }, + "address": { + "type": "string", + "description": "Wallet address." + }, + "contract": { + "type": "object", + "description": "The contract object that has details of a contract", + "properties": { + "address": { + "description": "Address of the held contract", + "type": "string" + }, + "name": { + "type": "string", + "description": "String - NFT contract name." + }, + "symbol": { + "type": "string", + "description": "String - NFT contract symbol abbreviation." + }, + "totalSupply": { + "type": "string", + "description": "String - Total number of NFTs in a given NFT collection." + }, + "tokenType": { + "type": "string", + "enum": [ + "ERC721", + "ERC1155", + "NO_SUPPORTED_NFT_STANDARD", + "NOT_A_CONTRACT" + ], + "description": "String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address." + }, + "contractDeployer": { + "type": "string", + "description": "String - Address that deployed the smart contract" + }, + "deployedBlockNumber": { + "type": "number", + "description": "Number - The Block Number when the deployment transaction is successfully mined" + }, + "openseaMetadata": { + "type": "object", + "description": "Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks.", + "properties": { + "floorPrice": { + "type": "number", + "description": "NFT floor price" + }, + "collectionName": { + "type": "string", + "description": "OpenSea collection name" + }, + "safelistRequestStatus": { + "type": "string", + "description": "Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model" + }, + "imageUrl": { + "type": "string", + "description": "OpenSea CDN image URL" + }, + "description": { + "type": "string", + "description": "OpenSea collection description. Note: this value is truncated to 255 characters." + }, + "externalUrl": { + "type": "string", + "description": "Collection homepage" + }, + "twitterUsername": { + "type": "string", + "description": "The twitter username of the collection" + }, + "discordUrl": { + "type": "string", + "description": "The discord URL of the collection" + }, + "bannerImageUrl": { + "type": "string", + "description": "The banner image URL of the collection" + }, + "lastIngestedAt": { + "type": "string", + "description": "The timestamp when the collection was last ingested by us" + } + } + }, + "isSpam": { + "type": "string", + "description": "\"true\" if contract is spam, else \"false\". **Only available on paid tiers.**" + }, + "spamClassifications": { + "description": "List of reasons why a contract was classified as spam. **Only available on paid tiers.**", + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "TransactionHistoryResponse": { + "type": "object", + "properties": { + "before": { + "type": "string", + "description": "The cursor that points to the previous set of results." + }, + "after": { + "type": "string", + "description": "The cursor that points to the end of the current set of results." + }, + "totalCount": { + "type": "integer", + "description": "Total count of the response items." + }, + "transactions": { + "type": "array", + "description": "List of transactions by address.", + "items": { + "type": "object", + "properties": { + "network": { + "type": "string", + "description": "Network associated with an individual transaction" + }, + "hash": { + "type": "string", + "description": "Transaction hash" + }, + "timeStamp": { + "type": "string", + "description": "(ISO 8601) Timestamp of transaction mining / confirmation" + }, + "blockNumber": { + "type": "integer", + "description": "Block number of transaction mining / confirmation" + }, + "blockHash": { + "type": "string", + "description": "Block hash of transaction mining / confirmation" + }, + "nonce": { + "type": "integer", + "description": "Transaction nonce" + }, + "transactionIndex": { + "type": "integer", + "description": "Position of transaction within a block" + }, + "fromAddress": { + "type": "string", + "description": "From address of transaction (hex string)." + }, + "toAddress": { + "type": "string", + "description": "To address of transaction (hex string). null if contract creation." + }, + "contractAddress": { + "type": "string", + "description": "20 Bytes - The contract address created, if the transaction was a contract creation, otherwise null" + }, + "value": { + "type": "string", + "description": "(uint8) Value of native token value moved within the external transaction" + }, + "cumulativeGasUsed": { + "type": "string", + "description": "The total amount of gas used when this transaction was executed in the block." + }, + "effectiveGasPrice": { + "type": "string", + "description": "Gas price parameter" + }, + "gasUsed": { + "type": "string", + "description": "The amount of gas used by this specific transaction alone" + }, + "logs": { + "type": "array", + "description": "Array of log objects, which this transaction generated", + "items": { + "type": "object", + "properties": { + "contractAddress": { + "type": "string", + "description": "20 Bytes - contract address from which this log originated." + }, + "logIndex": { + "type": "string", + "description": "Integer of the log index position in the block. null when its pending log." + }, + "data": { + "type": "string", + "description": "Contains one or more 32 Bytes non-indexed arguments of the log." + }, + "removed": { + "type": "boolean", + "description": "true when the log was removed, due to a chain reorganization. false if its a valid log." + }, + "topics": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of zero to four 32 Bytes DATA of indexed log arguments" + } + } + } + }, + "internalTxns": { + "type": "array", + "description": "Array of internal transaction objects, which this transaction generated", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "CALL or CREATE" + }, + "fromAddress": { + "type": "string", + "description": "20 Bytes - address of the sender" + }, + "toAddress": { + "type": "string", + "description": "20 Bytes - address of the receiver. null when its a contract creation transaction" + }, + "value": { + "type": "string", + "description": "amount of value for transfer (in hex)" + }, + "gas": { + "type": "string", + "description": "amount of gas provided for the call (in hex)" + }, + "gasUsed": { + "type": "string", + "description": "amount of gas used during the call (in hex)" + }, + "input": { + "type": "string", + "description": "call data" + }, + "output": { + "type": "string", + "description": "return data" + }, + "error": { + "type": "string", + "description": "error, if any" + }, + "revertReason": { + "type": "string", + "description": "solidity revert reason, if any" + } + } + } + } + } + } + } + }, + "required": [ + "transactions" + ] + }, + "TransactionHistoryResponseItem": { + "type": "object", + "properties": { + "network": { + "type": "string", + "description": "Network associated with an individual transaction" + }, + "hash": { + "type": "string", + "description": "Transaction hash" + }, + "timeStamp": { + "type": "string", + "description": "(ISO 8601) Timestamp of transaction mining / confirmation" + }, + "blockNumber": { + "type": "integer", + "description": "Block number of transaction mining / confirmation" + }, + "blockHash": { + "type": "string", + "description": "Block hash of transaction mining / confirmation" + }, + "nonce": { + "type": "integer", + "description": "Transaction nonce" + }, + "transactionIndex": { + "type": "integer", + "description": "Position of transaction within a block" + }, + "fromAddress": { + "type": "string", + "description": "From address of transaction (hex string)." + }, + "toAddress": { + "type": "string", + "description": "To address of transaction (hex string). null if contract creation." + }, + "contractAddress": { + "type": "string", + "description": "20 Bytes - The contract address created, if the transaction was a contract creation, otherwise null" + }, + "value": { + "type": "string", + "description": "(uint8) Value of native token value moved within the external transaction" + }, + "cumulativeGasUsed": { + "type": "string", + "description": "The total amount of gas used when this transaction was executed in the block." + }, + "effectiveGasPrice": { + "type": "string", + "description": "Gas price parameter" + }, + "gasUsed": { + "type": "string", + "description": "The amount of gas used by this specific transaction alone" + }, + "logs": { + "type": "array", + "description": "Array of log objects, which this transaction generated", + "items": { + "type": "object", + "properties": { + "contractAddress": { + "type": "string", + "description": "20 Bytes - contract address from which this log originated." + }, + "logIndex": { + "type": "string", + "description": "Integer of the log index position in the block. null when its pending log." + }, + "data": { + "type": "string", + "description": "Contains one or more 32 Bytes non-indexed arguments of the log." + }, + "removed": { + "type": "boolean", + "description": "true when the log was removed, due to a chain reorganization. false if its a valid log." + }, + "topics": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of zero to four 32 Bytes DATA of indexed log arguments" + } + } + } + }, + "internalTxns": { + "type": "array", + "description": "Array of internal transaction objects, which this transaction generated", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "CALL or CREATE" + }, + "fromAddress": { + "type": "string", + "description": "20 Bytes - address of the sender" + }, + "toAddress": { + "type": "string", + "description": "20 Bytes - address of the receiver. null when its a contract creation transaction" + }, + "value": { + "type": "string", + "description": "amount of value for transfer (in hex)" + }, + "gas": { + "type": "string", + "description": "amount of gas provided for the call (in hex)" + }, + "gasUsed": { + "type": "string", + "description": "amount of gas used during the call (in hex)" + }, + "input": { + "type": "string", + "description": "call data" + }, + "output": { + "type": "string", + "description": "return data" + }, + "error": { + "type": "string", + "description": "error, if any" + }, + "revertReason": { + "type": "string", + "description": "solidity revert reason, if any" + } + } + } + } + } + }, + "TokenPricesResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "description": "List of token price data.", + "items": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "Token symbol." + }, + "prices": { + "type": "array", + "description": "List of price information.", + "items": { + "type": "object", + "properties": { + "currency": { + "type": "string", + "description": "Currency code (e.g., USD)." + }, + "value": { + "type": "string", + "description": "Price value as a string." + }, + "lastUpdatedAt": { + "type": "string", + "format": "date-time", + "description": "Time when the price was last updated." + } + }, + "required": [ + "currency", + "value", + "lastUpdatedAt" + ] + } + }, + "error": { + "type": [ + "string", + "null" + ], + "description": "Error message if applicable." + } + }, + "required": [ + "symbol", + "prices", + "error" + ] + } + } + }, + "required": [ + "data" + ] + }, + "TokenPriceResponseItem": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "Token symbol." + }, + "prices": { + "type": "array", + "description": "List of price information.", + "items": { + "type": "object", + "properties": { + "currency": { + "type": "string", + "description": "Currency code (e.g., USD)." + }, + "value": { + "type": "string", + "description": "Price value as a string." + }, + "lastUpdatedAt": { + "type": "string", + "format": "date-time", + "description": "Time when the price was last updated." + } + }, + "required": [ + "currency", + "value", + "lastUpdatedAt" + ] + } + }, + "error": { + "type": [ + "string", + "null" + ], + "description": "Error message if applicable." + } + }, + "required": [ + "symbol", + "prices", + "error" + ] + }, + "BlockTimestampResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "description": "List of blocks", + "items": { + "type": "object", + "properties": { + "network": { + "type": "string", + "description": "Network identifier" + }, + "block": { + "type": "object", + "properties": { + "number": { + "type": "integer", + "description": "Block number" + }, + "timestamp": { + "type": "string", + "description": "ISO timestamp of the block" + } + }, + "required": [ + "number", + "timestamp" + ] + } + }, + "required": [ + "network", + "block" + ] + } + } + }, + "required": [ + "data" + ] + } + } + } +} diff --git a/packages/api-codegen/specs/specs.lock.json b/packages/api-codegen/specs/specs.lock.json new file mode 100644 index 0000000000..c6953038ec --- /dev/null +++ b/packages/api-codegen/specs/specs.lock.json @@ -0,0 +1,12 @@ +{ + "docs": { + "repository": "alchemyplatform/docs", + "sha": "374030e02046972b4158612036af3aed9130b675", + "branch": "codex/improve-agent-wallet-docs" + }, + "specs": { + "nft.json": "c90282cfc4959f48534aaccceccdd31202ca1410888d7d0daafdd20e0f8c4885", + "portfolio.json": "16bad2001183fada4147f445640555e22a0c58ad44844eefdf0a06e3f794774c", + "transfers.json": "17626a215d7453b41a868e434d5d86a9a1505d8e648ca91c7df1b44c97af9cf5" + } +} diff --git a/packages/api-codegen/specs/transfers.json b/packages/api-codegen/specs/transfers.json new file mode 100644 index 0000000000..b4b6ef8339 --- /dev/null +++ b/packages/api-codegen/specs/transfers.json @@ -0,0 +1,566 @@ +{ + "$schema": "https://meta.open-rpc.org/", + "openrpc": "1.2.4", + "info": { + "title": "Alchemy Transfers API JSON-RPC Specification", + "description": "A specification of the standard JSON-RPC methods for Transfers API.", + "version": "0.0.0" + }, + "servers": [ + { + "url": "https://eth-mainnet.g.alchemy.com/v2", + "name": "Ethereum Mainnet" + }, + { + "url": "https://eth-mainnetbeacon.g.alchemy.com/v2", + "name": "Ethereum Mainnet Beacon" + }, + { + "url": "https://eth-hoodi.g.alchemy.com/v2", + "name": "Ethereum Hoodi" + }, + { + "url": "https://eth-hoodibeacon.g.alchemy.com/v2", + "name": "Ethereum Hoodi Beacon" + }, + { + "url": "https://eth-sepolia.g.alchemy.com/v2", + "name": "Ethereum Sepolia" + }, + { + "url": "https://eth-sepoliabeacon.g.alchemy.com/v2", + "name": "Ethereum Sepolia Beacon" + }, + { + "url": "https://abstract-mainnet.g.alchemy.com/v2", + "name": "Abstract Mainnet" + }, + { + "url": "https://abstract-testnet.g.alchemy.com/v2", + "name": "Abstract Testnet" + }, + { + "url": "https://anime-mainnet.g.alchemy.com/v2", + "name": "Anime Mainnet" + }, + { + "url": "https://anime-sepolia.g.alchemy.com/v2", + "name": "Anime Sepolia" + }, + { + "url": "https://apechain-mainnet.g.alchemy.com/v2", + "name": "ApeChain Mainnet" + }, + { + "url": "https://apechain-curtis.g.alchemy.com/v2", + "name": "ApeChain Curtis" + }, + { + "url": "https://arb-mainnet.g.alchemy.com/v2", + "name": "Arbitrum Mainnet" + }, + { + "url": "https://arb-sepolia.g.alchemy.com/v2", + "name": "Arbitrum Sepolia" + }, + { + "url": "https://avax-mainnet.g.alchemy.com/v2", + "name": "Avalanche Mainnet" + }, + { + "url": "https://avax-fuji.g.alchemy.com/v2", + "name": "Avalanche Fuji" + }, + { + "url": "https://base-mainnet.g.alchemy.com/v2", + "name": "Base Mainnet" + }, + { + "url": "https://base-sepolia.g.alchemy.com/v2", + "name": "Base Sepolia" + }, + { + "url": "https://berachain-mainnet.g.alchemy.com/v2", + "name": "Berachain Mainnet" + }, + { + "url": "https://berachain-bepolia.g.alchemy.com/v2", + "name": "Berachain Bepolia" + }, + { + "url": "https://blast-mainnet.g.alchemy.com/v2", + "name": "Blast Mainnet" + }, + { + "url": "https://blast-sepolia.g.alchemy.com/v2", + "name": "Blast Sepolia" + }, + { + "url": "https://bnb-mainnet.g.alchemy.com/v2", + "name": "BNB Smart Chain Mainnet" + }, + { + "url": "https://bnb-testnet.g.alchemy.com/v2", + "name": "BNB Smart Chain Testnet" + }, + { + "url": "https://celo-mainnet.g.alchemy.com/v2", + "name": "Celo Mainnet" + }, + { + "url": "https://celo-sepolia.g.alchemy.com/v2", + "name": "Celo Sepolia" + }, + { + "url": "https://gensyn-mainnet.g.alchemy.com/v2", + "name": "Gensyn Mainnet" + }, + { + "url": "https://gensyn-testnet.g.alchemy.com/v2", + "name": "Gensyn Testnet" + }, + { + "url": "https://gnosis-mainnet.g.alchemy.com/v2", + "name": "Gnosis Mainnet" + }, + { + "url": "https://gnosis-chiado.g.alchemy.com/v2", + "name": "Gnosis Chiado" + }, + { + "url": "https://hyperliquid-mainnet.g.alchemy.com/v2", + "name": "Hyperliquid Mainnet" + }, + { + "url": "https://hyperliquid-testnet.g.alchemy.com/v2", + "name": "Hyperliquid Testnet" + }, + { + "url": "https://ink-mainnet.g.alchemy.com/v2", + "name": "Ink Mainnet" + }, + { + "url": "https://ink-sepolia.g.alchemy.com/v2", + "name": "Ink Sepolia" + }, + { + "url": "https://lens-mainnet.g.alchemy.com/v2", + "name": "Lens Mainnet" + }, + { + "url": "https://lens-sepolia.g.alchemy.com/v2", + "name": "Lens Sepolia" + }, + { + "url": "https://linea-mainnet.g.alchemy.com/v2", + "name": "Linea Mainnet" + }, + { + "url": "https://linea-sepolia.g.alchemy.com/v2", + "name": "Linea Sepolia" + }, + { + "url": "https://polygon-mainnet.g.alchemy.com/v2", + "name": "Polygon Mainnet" + }, + { + "url": "https://polygon-amoy.g.alchemy.com/v2", + "name": "Polygon Amoy" + }, + { + "url": "https://monad-mainnet.g.alchemy.com/v2", + "name": "Monad Mainnet" + }, + { + "url": "https://monad-testnet.g.alchemy.com/v2", + "name": "Monad Testnet" + }, + { + "url": "https://mythos-mainnet.g.alchemy.com/v2", + "name": "Mythos Mainnet" + }, + { + "url": "https://opt-mainnet.g.alchemy.com/v2", + "name": "OP Mainnet Mainnet" + }, + { + "url": "https://opt-sepolia.g.alchemy.com/v2", + "name": "OP Mainnet Sepolia" + }, + { + "url": "https://robinhood-testnet.g.alchemy.com/v2", + "name": "Robinhood Chain Testnet" + }, + { + "url": "https://ronin-mainnet.g.alchemy.com/v2", + "name": "Ronin Mainnet" + }, + { + "url": "https://ronin-saigon.g.alchemy.com/v2", + "name": "Ronin Saigon" + }, + { + "url": "https://rootstock-mainnet.g.alchemy.com/v2", + "name": "Rootstock Mainnet" + }, + { + "url": "https://rootstock-testnet.g.alchemy.com/v2", + "name": "Rootstock Testnet" + }, + { + "url": "https://scroll-mainnet.g.alchemy.com/v2", + "name": "Scroll Mainnet" + }, + { + "url": "https://scroll-sepolia.g.alchemy.com/v2", + "name": "Scroll Sepolia" + }, + { + "url": "https://settlus-mainnet.g.alchemy.com/v2", + "name": "Settlus Mainnet" + }, + { + "url": "https://settlus-septestnet.g.alchemy.com/v2", + "name": "Settlus Sepolia" + }, + { + "url": "https://shape-mainnet.g.alchemy.com/v2", + "name": "Shape Mainnet" + }, + { + "url": "https://shape-sepolia.g.alchemy.com/v2", + "name": "Shape Sepolia" + }, + { + "url": "https://soneium-mainnet.g.alchemy.com/v2", + "name": "Soneium Mainnet" + }, + { + "url": "https://soneium-minato.g.alchemy.com/v2", + "name": "Soneium Minato" + }, + { + "url": "https://story-mainnet.g.alchemy.com/v2", + "name": "Story Mainnet" + }, + { + "url": "https://story-aeneid.g.alchemy.com/v2", + "name": "Story Aeneid" + }, + { + "url": "https://unichain-mainnet.g.alchemy.com/v2", + "name": "Unichain Mainnet" + }, + { + "url": "https://unichain-sepolia.g.alchemy.com/v2", + "name": "Unichain Sepolia" + }, + { + "url": "https://worldchain-mainnet.g.alchemy.com/v2", + "name": "World Chain Mainnet" + }, + { + "url": "https://worldchain-sepolia.g.alchemy.com/v2", + "name": "World Chain Sepolia" + }, + { + "url": "https://zetachain-mainnet.g.alchemy.com/v2", + "name": "ZetaChain Mainnet" + }, + { + "url": "https://zetachain-testnet.g.alchemy.com/v2", + "name": "ZetaChain Testnet" + }, + { + "url": "https://zksync-mainnet.g.alchemy.com/v2", + "name": "ZKsync Mainnet" + }, + { + "url": "https://zksync-sepolia.g.alchemy.com/v2", + "name": "ZKsync Sepolia" + }, + { + "url": "https://zora-mainnet.g.alchemy.com/v2", + "name": "Zora Mainnet" + }, + { + "url": "https://zora-sepolia.g.alchemy.com/v2", + "name": "Zora Sepolia" + } + ], + "methods": [ + { + "name": "alchemy_getAssetTransfers", + "description": "The Transfers API allows you to easily fetch historical transactions for any address across Ethereum and supported L2s including Base, Polygon, Arbitrum, and Optimism (internal transfer data is only available on Ethereum Mainnet and Polygon Mainnet).", + "x-compute-units": 120, + "params": [ + { + "name": "assetTransferParams", + "required": true, + "schema": { + "type": "object", + "properties": { + "fromBlock": { + "type": "string", + "default": "0x0" + }, + "toBlock": { + "type": "string", + "default": "latest" + }, + "fromAddress": { + "type": "string", + "default": "0x0000000000000000000000000000000000000000" + }, + "toAddress": { + "type": "string", + "default": "0x0000000000000000000000000000000000000000" + }, + "excludeZeroValue": { + "type": "boolean", + "default": true + }, + "category": { + "type": "array", + "description": "Array of transfer categories to include. Note: 'internal' category is not supported on Base, it is only available on Ethereum Mainnet and Polygon Mainnet.", + "items": { + "type": "string", + "enum": [ + "external", + "internal", + "erc20", + "erc721", + "erc1155", + "specialnft" + ] + } + }, + "contractAddresses": { + "type": "array", + "description": "An array of contract addresses to filter for.", + "items": { + "type": "string" + } + }, + "order": { + "type": "string", + "enum": [ + "asc", + "desc" + ] + }, + "withMetadata": { + "type": "boolean", + "description": "Available only on ETH, Base, Polygon, Arbitrum, Optimism", + "default": false + }, + "maxCount": { + "type": "string", + "default": "0x3e8" + }, + "pageKey": { + "type": "string", + "default": "0x0" + } + } + } + } + ], + "result": { + "name": "Asset transfers", + "description": "Returns the list of transfers, and a pageKey if additional results remain.", + "schema": { + "oneOf": [ + { + "title": "Not Found (null)", + "type": "string" + }, + { + "type": "object", + "properties": { + "pageKey": { + "type": "string", + "description": "Uuid of next page of results (if exists, else blank)." + }, + "transfers": { + "type": "array", + "description": "Array of transfer objects sorted in ascending or descending order by block number.", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "description": "'external', 'internal', 'token', 'erc20', 'erc721', 'erc1155', 'specialnft'" + }, + "blockNum": { + "type": "string", + "description": "Block number of the transfer (hex string)." + }, + "from": { + "type": "string", + "description": "From address (hex string)." + }, + "to": { + "type": "string", + "description": "To address (hex string). null if contract creation." + }, + "value": { + "type": "number", + "nullable": true, + "description": "Asset transfer value. null if it's an ERC721 or unknown decimals." + }, + "erc721TokenId": { + "type": "string", + "nullable": true, + "description": "(Deprecated) Legacy token ID field for ERC721 tokens. Use `tokenId` instead." + }, + "erc1155Metadata": { + "type": "array", + "nullable": true, + "description": "Array of objects with (tokenId, value) for ERC1155 transfers, null otherwise.", + "items": { + "type": "object", + "properties": { + "tokenId": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + }, + "tokenId": { + "type": "string", + "description": "Token ID for NFT tokens (ERC721, ERC1155, etc.)." + }, + "asset": { + "type": "string", + "nullable": true, + "description": "ETH or the token's symbol. null if unavailable." + }, + "uniqueId": { + "type": "string", + "description": "Unique identifier for the transfer object." + }, + "hash": { + "type": "string", + "description": "Transaction hash (hex string)." + }, + "rawContract": { + "type": "object", + "properties": { + "value": { + "type": "string", + "nullable": true, + "description": "Raw hex transfer value. null for NFT transfers." + }, + "address": { + "type": "string", + "nullable": true, + "description": "Contract address (hex string). null for external or internal transfers." + }, + "decimal": { + "type": "string", + "nullable": true, + "description": "Contract decimal in hex. null if not known." + } + } + }, + "metadata": { + "type": "object", + "properties": { + "blockTimestamp": { + "type": "string", + "description": "ISO-formatted timestamp of the block containing this transfer. (Available only on ETH, Base, Polygon, Arbitrum, Optimism)" + } + } + } + } + } + } + } + } + ] + } + }, + "examples": [ + { + "name": "alchemy_getAssetTransfers example", + "params": [ + { + "name": "assetTransferParams", + "value": { + "fromBlock": "0x0", + "fromAddress": "0x0000000000000000000000000000000000000000", + "toAddress": "0x5c43B1eD97e52d009611D89b74fA829FE4ac56b1", + "excludeZeroValue": true, + "withMetadata": true, + "category": [ + "erc721", + "erc1155" + ] + } + } + ], + "result": { + "name": "Asset transfers", + "value": { + "transfers": [ + { + "blockNum": "0xb0eadc", + "uniqueId": "0x3847245c01829b043431067fb2bfa95f7b5bdc7e4246c843e7a573ab6f26f5ff:external", + "hash": "0x3847245c01829b043431067fb2bfa95f7b5bdc7e4246c843e7a573ab6f26f5ff", + "from": "0xef4396d9ff8107086d215a1c9f8866c54795d7c7", + "to": "0x5c43b1ed97e52d009611d89b74fa829fe4ac56b1", + "value": 0.5, + "erc721TokenId": null, + "erc1155Metadata": null, + "tokenId": null, + "asset": "ETH", + "category": "external", + "rawContract": { + "value": "0x6f05b59d3b20000", + "address": null, + "decimal": "0x12" + } + }, + { + "blockNum": "0xb96042", + "uniqueId": "0x5c88806ce2e4a42c5fbd5804f340ed887995914546cf92ec39eb5472cf22c88c:external", + "hash": "0x5c88806ce2e4a42c5fbd5804f340ed887995914546cf92ec39eb5472cf22c88c", + "from": "0xef4396d9ff8107086d215a1c9f8866c54795d7c7", + "to": "0x5c43b1ed97e52d009611d89b74fa829fe4ac56b1", + "value": 0.27, + "erc721TokenId": null, + "erc1155Metadata": null, + "tokenId": null, + "asset": "ETH", + "category": "external", + "rawContract": { + "value": "0x3bf3b91c95b0000", + "address": null, + "decimal": "0x12" + } + } + ], + "pageKey": "" + } + } + } + ] + } + ], + "x-auth-params": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + } + ] +} diff --git a/packages/api-codegen/src/cli.ts b/packages/api-codegen/src/cli.ts new file mode 100644 index 0000000000..bc273cd62a --- /dev/null +++ b/packages/api-codegen/src/cli.ts @@ -0,0 +1,37 @@ +import { generate } from "./generate.js"; +import { snapshot } from "./snapshot.js"; + +/** + * CLI entrypoint. + * + * tsx src/cli.ts snapshot [--docs ] [--allow-dirty] + * tsx src/cli.ts --target + */ +async function main(): Promise { + const args = process.argv.slice(2); + + if (args[0] === "snapshot") { + const docsFlag = args.indexOf("--docs"); + await snapshot({ + docsDir: docsFlag !== -1 ? args[docsFlag + 1] : undefined, + allowDirty: args.includes("--allow-dirty"), + }); + return; + } + + const targetFlag = args.indexOf("--target"); + if (targetFlag !== -1 && args[targetFlag + 1]) { + await generate(args[targetFlag + 1]); + return; + } + + console.error( + "Usage: cli.ts snapshot [--docs ] [--allow-dirty] | cli.ts --target ", + ); + process.exit(1); +} + +main().catch((error) => { + console.error(error instanceof Error ? error.message : error); + process.exit(1); +}); diff --git a/packages/api-codegen/src/errors.ts b/packages/api-codegen/src/errors.ts new file mode 100644 index 0000000000..6a5bee6a7d --- /dev/null +++ b/packages/api-codegen/src/errors.ts @@ -0,0 +1,7 @@ +/** + * Error type for all failures raised by the codegen tool (manifest/spec + * mismatches, lockfile checksum failures, malformed specs). + */ +export class CodegenError extends Error { + override name = "CodegenError"; +} diff --git a/packages/api-codegen/src/format.ts b/packages/api-codegen/src/format.ts new file mode 100644 index 0000000000..ef07525d3e --- /dev/null +++ b/packages/api-codegen/src/format.ts @@ -0,0 +1,29 @@ +import prettier from "prettier"; + +const BANNER = `/* eslint-disable -- machine-generated file */ +// AUTO-GENERATED by @alchemy/api-codegen — DO NOT EDIT. +// Regenerate with \`pnpm generate\`. Spec provenance (docs repo commit + checksums) +// is recorded in packages/api-codegen/specs/specs.lock.json. + +`; + +/** + * Prepends the do-not-edit banner and formats generated TypeScript with the + * repo's prettier config (resolved from the output file's location, exactly + * as `prettier --write` would). Generated files are excluded from lint, so + * the generator is responsible for producing stable, formatted output. + * + * @param {string} source Generated TypeScript source (without banner) + * @param {string} outputPath Absolute output path used to resolve prettier config + * @returns {Promise} Banner + formatted source + */ +export async function formatGenerated( + source: string, + outputPath: string, +): Promise { + const config = await prettier.resolveConfig(outputPath); + return prettier.format(BANNER + source, { + ...config, + parser: "typescript", + }); +} diff --git a/packages/api-codegen/src/generate.ts b/packages/api-codegen/src/generate.ts new file mode 100644 index 0000000000..c9788c2433 --- /dev/null +++ b/packages/api-codegen/src/generate.ts @@ -0,0 +1,81 @@ +import { resolve } from "node:path"; +import { CodegenError } from "./errors.js"; +import { formatGenerated } from "./format.js"; +import { + loadManifest, + validateRestManifest, + validateRpcManifest, +} from "./manifest.js"; +import { REPO_ROOT } from "./paths.js"; +import { emitRestSchema } from "./rest/schemaEmitter.js"; +import { generateOpenapiTypes } from "./rest/openapiTypes.js"; +import { emitRpcSchema } from "./rpc/rpcEmitter.js"; +import { readSnapshot } from "./snapshot.js"; +import { TARGETS } from "./targets.js"; +import { writeIfChanged } from "./write.js"; + +/** + * Formats and writes one generated file, logging the outcome. + * + * @param {string} outputPath Absolute output path + * @param {string} source Generated source (unformatted, no banner) + */ +async function emitFile(outputPath: string, source: string): Promise { + const formatted = await formatGenerated(source, outputPath); + const wrote = writeIfChanged(outputPath, formatted); + console.log( + ` ${outputPath.replace(REPO_ROOT + "/", "")} ${wrote ? "written" : "unchanged"}`, + ); +} + +/** + * Generates a target's `src/generated/` internals from the committed spec + * snapshots (offline + deterministic). Hard-errors if the target's manifest + * references operations/methods missing from the snapshots. + * + * @param {string} targetName A key of TARGETS (e.g. "data-apis") + */ +export async function generate(targetName: string): Promise { + const target = TARGETS[targetName]; + if (!target) { + throw new CodegenError( + `Unknown target "${targetName}". Registered: ${Object.keys(TARGETS).join(", ")}.`, + ); + } + const packageDir = resolve(REPO_ROOT, target.packageDir); + const outputDir = resolve(packageDir, target.outputDir); + const manifest = await loadManifest(resolve(packageDir, target.manifestPath)); + console.log(`Generating ${target.packageDir}/${target.outputDir} ...`); + + for (const restConfig of manifest.rest) { + const spec = readSnapshot(restConfig.spec); + const uncovered = validateRestManifest(restConfig, spec); + if (uncovered.length > 0) { + console.warn( + ` note: spec "${restConfig.spec}" has ${uncovered.length} operation(s) not in the manifest: ${uncovered.join(", ")}`, + ); + } + await emitFile( + resolve(outputDir, `rest/${restConfig.spec}.types.ts`), + await generateOpenapiTypes(spec), + ); + await emitFile( + resolve(outputDir, `rest/${restConfig.spec}.schema.ts`), + emitRestSchema(restConfig, spec), + ); + } + + for (const rpcConfig of manifest.rpc) { + const spec = readSnapshot(rpcConfig.spec); + const uncovered = validateRpcManifest(rpcConfig, spec); + if (uncovered.length > 0) { + console.warn( + ` note: spec "${rpcConfig.spec}" has ${uncovered.length} method(s) not in the manifest: ${uncovered.join(", ")}`, + ); + } + await emitFile( + resolve(outputDir, `rpc/${rpcConfig.spec}.ts`), + await emitRpcSchema(rpcConfig, spec), + ); + } +} diff --git a/packages/api-codegen/src/hash.ts b/packages/api-codegen/src/hash.ts new file mode 100644 index 0000000000..679abcf29b --- /dev/null +++ b/packages/api-codegen/src/hash.ts @@ -0,0 +1,12 @@ +import { createHash } from "node:crypto"; + +/** + * Computes the sha256 hex digest of a string, used to pin spec snapshots in + * specs.lock.json and verify them at generate time. + * + * @param {string} content The content to hash + * @returns {string} The sha256 hex digest + */ +export function sha256(content: string): string { + return createHash("sha256").update(content, "utf8").digest("hex"); +} diff --git a/packages/api-codegen/src/index.ts b/packages/api-codegen/src/index.ts new file mode 100644 index 0000000000..ed41b98c0f --- /dev/null +++ b/packages/api-codegen/src/index.ts @@ -0,0 +1,10 @@ +// Public (workspace-internal) surface: the manifest types targets use to +// author their codegen.manifest.ts. +export type { + CodegenManifest, + PathRules, + RestOperationConfig, + RestSpecConfig, + RpcMethodConfig, + RpcSpecConfig, +} from "./manifest.js"; diff --git a/packages/api-codegen/src/manifest.ts b/packages/api-codegen/src/manifest.ts new file mode 100644 index 0000000000..f4b1f09d09 --- /dev/null +++ b/packages/api-codegen/src/manifest.ts @@ -0,0 +1,152 @@ +import { pathToFileURL } from "node:url"; +import { CodegenError } from "./errors.js"; + +/** Path → Route normalization rules for a REST spec (see normalizePath). */ +export type PathRules = { + /** Drop `{apiKey}` path segments (runtime auth is header-based). Default true. */ + stripApiKeySegment?: boolean; + /** Prefix already present in the runtime base URL (e.g. "/v3" for NFT). */ + stripPrefix?: string; +}; + +/** A single OpenAPI operation the target consumes. */ +export type RestOperationConfig = { + /** operationId as it appears in the spec (e.g. "getNFTsForOwner-v3"). */ + operationId: string; + /** Base for emitted type names (e.g. "GetNftsForOwner" → GetNftsForOwnerResponse). */ + exportBaseName: string; + /** Also emit a named query-params type (GET endpoints; RestRequestSchema has no query channel). */ + emitQueryType?: boolean; +}; + +/** One REST spec consumed by the target. */ +export type RestSpecConfig = { + /** Snapshot basename without extension (specs/.json). */ + spec: string; + /** Name of the emitted RestRequestSchema tuple type (e.g. "PortfolioRestSchema"). */ + schemaTypeName: string; + pathRules?: PathRules; + operations: RestOperationConfig[]; +}; + +/** A single OpenRPC method the target consumes. */ +export type RpcMethodConfig = { + /** JSON-RPC method name as it appears in the spec (e.g. "alchemy_getAssetTransfers"). */ + method: string; + /** Base for emitted type names (e.g. "AlchemyGetAssetTransfers"). */ + exportBaseName: string; +}; + +/** One OpenRPC spec consumed by the target. */ +export type RpcSpecConfig = { + /** Snapshot basename without extension (specs/.json). */ + spec: string; + /** Name of the emitted viem RpcSchema tuple type (e.g. "TransfersRpcSchema"). */ + schemaTypeName: string; + methods: RpcMethodConfig[]; +}; + +/** + * The per-target overlay manifest: the hand-maintained mapping from spec + * operations to the SDK's generated type surface. Validated against the spec + * snapshots on every generate run — a referenced operation missing from the + * snapshot is a hard error (the drift alarm). + */ +export type CodegenManifest = { + rest: RestSpecConfig[]; + rpc: RpcSpecConfig[]; +}; + +/** + * Loads a target's codegen.manifest.ts (default export). + * + * @param {string} manifestPath Absolute path to the manifest module + * @returns {Promise} The manifest + */ +export async function loadManifest( + manifestPath: string, +): Promise { + const mod = await import(pathToFileURL(manifestPath).href); + const manifest = mod.default as CodegenManifest | undefined; + if ( + !manifest || + !Array.isArray(manifest.rest) || + !Array.isArray(manifest.rpc) + ) { + throw new CodegenError( + `Manifest at ${manifestPath} must default-export a CodegenManifest ({ rest, rpc }).`, + ); + } + return manifest; +} + +/** + * Validates that every operationId a REST manifest entry references exists in + * the spec snapshot, and reports spec operations the manifest doesn't cover. + * + * @param {RestSpecConfig} config The manifest entry for this spec + * @param {Record} spec The parsed OpenAPI snapshot + * @returns {string[]} operationIds present in the spec but not in the manifest (new-endpoint visibility) + */ +export function validateRestManifest( + config: RestSpecConfig, + spec: Record, +): string[] { + const specOperationIds = new Set(); + const paths = (spec.paths ?? {}) as Record< + string, + Record + >; + for (const methods of Object.values(paths)) { + for (const op of Object.values(methods)) { + if (op && typeof op === "object" && op.operationId) { + specOperationIds.add(op.operationId); + } + } + } + + const missing = config.operations + .map((o) => o.operationId) + .filter((id) => !specOperationIds.has(id)); + if (missing.length > 0) { + throw new CodegenError( + `Spec "${config.spec}" no longer contains operationId(s) referenced by the manifest: ${missing.join(", ")}. ` + + `The upstream spec was likely renamed or removed — update the manifest (and the SDK surface) deliberately.`, + ); + } + + const covered = new Set(config.operations.map((o) => o.operationId)); + return [...specOperationIds].filter((id) => !covered.has(id)).sort(); +} + +/** + * Validates that every RPC method a manifest entry references exists in the + * OpenRPC snapshot, and reports spec methods the manifest doesn't cover. + * + * @param {RpcSpecConfig} config The manifest entry for this spec + * @param {Record} spec The parsed OpenRPC snapshot + * @returns {string[]} methods present in the spec but not in the manifest + */ +export function validateRpcManifest( + config: RpcSpecConfig, + spec: Record, +): string[] { + const specMethods = new Set( + ((spec.methods ?? []) as Array<{ name?: string }>) + .map((m) => m.name) + .filter((name): name is string => typeof name === "string"), + ); + + const missing = config.methods + .map((m) => m.method) + .filter((name) => !specMethods.has(name)); + if (missing.length > 0) { + throw new CodegenError( + `Spec "${config.spec}" no longer contains RPC method(s) referenced by the manifest: ${missing.join(", ")}. ` + + `The upstream spec was likely renamed or removed — update the manifest (and the SDK surface) deliberately.`, + ); + } + + const covered = new Set(config.methods.map((m) => m.method)); + return [...specMethods].filter((name) => !covered.has(name)).sort(); +} diff --git a/packages/api-codegen/src/paths.ts b/packages/api-codegen/src/paths.ts new file mode 100644 index 0000000000..8e17b3db14 --- /dev/null +++ b/packages/api-codegen/src/paths.ts @@ -0,0 +1,17 @@ +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +/** Absolute path of the api-codegen package directory. */ +export const PACKAGE_DIR = resolve( + dirname(fileURLToPath(import.meta.url)), + "..", +); + +/** Absolute path of the aa-sdk repo root. */ +export const REPO_ROOT = resolve(PACKAGE_DIR, "../.."); + +/** Absolute path of the committed spec snapshots directory. */ +export const SPECS_DIR = resolve(PACKAGE_DIR, "specs"); + +/** Absolute path of the snapshot lockfile. */ +export const LOCKFILE_PATH = resolve(SPECS_DIR, "specs.lock.json"); diff --git a/packages/api-codegen/src/rest/normalizePath.ts b/packages/api-codegen/src/rest/normalizePath.ts new file mode 100644 index 0000000000..805a5c92d7 --- /dev/null +++ b/packages/api-codegen/src/rest/normalizePath.ts @@ -0,0 +1,45 @@ +import type { PathRules } from "../manifest.js"; +import { CodegenError } from "../errors.js"; + +/** + * Normalizes an OpenAPI spec path into the Route literal the SDK's REST + * client uses at runtime. Docs specs embed auth and version prefixes in the + * path (e.g. "/v3/{apiKey}/getNFTsForOwner"); the runtime uses header auth + * against base URLs that already carry the prefix, so Routes are relative + * (e.g. "getNFTsForOwner"). + * + * Rules, in order: drop `{apiKey}` segments (default on), strip the + * configured prefix, strip leading slashes. + * + * @param {string} specPath The path as it appears in the spec + * @param {PathRules} [rules] Per-spec normalization rules from the manifest + * @returns {string} The normalized Route literal + */ +export function normalizePath(specPath: string, rules?: PathRules): string { + let path = specPath; + + if (rules?.stripApiKeySegment !== false) { + path = path + .split("/") + .filter((segment) => segment !== "{apiKey}") + .join("/"); + } + + if (rules?.stripPrefix) { + if (!path.startsWith(rules.stripPrefix)) { + throw new CodegenError( + `Path "${specPath}" does not start with configured stripPrefix "${rules.stripPrefix}" ` + + `(after apiKey-segment removal: "${path}"). The upstream path layout changed — update the manifest.`, + ); + } + path = path.slice(rules.stripPrefix.length); + } + + const route = path.replace(/^\/+/, ""); + if (route.length === 0) { + throw new CodegenError( + `Path "${specPath}" normalized to an empty route with rules ${JSON.stringify(rules ?? {})}.`, + ); + } + return route; +} diff --git a/packages/api-codegen/src/rest/openapiTypes.ts b/packages/api-codegen/src/rest/openapiTypes.ts new file mode 100644 index 0000000000..5d302ab009 --- /dev/null +++ b/packages/api-codegen/src/rest/openapiTypes.ts @@ -0,0 +1,17 @@ +import openapiTS, { astToString } from "openapi-typescript"; + +/** + * Runs openapi-typescript over a bundled (dereferenced) OpenAPI document and + * returns the generated source (paths/components/operations interfaces). + * + * @param {Record} spec The parsed OpenAPI snapshot + * @returns {Promise} Generated TypeScript source (unformatted, no banner) + */ +export async function generateOpenapiTypes( + spec: Record, +): Promise { + // openapi-typescript accepts an in-memory document; snapshots are already + // dereferenced by the docs repo's bundling, so no $ref resolution happens here. + const ast = await openapiTS(spec as Parameters[0]); + return astToString(ast); +} diff --git a/packages/api-codegen/src/rest/schemaEmitter.ts b/packages/api-codegen/src/rest/schemaEmitter.ts new file mode 100644 index 0000000000..ffd16f2ecc --- /dev/null +++ b/packages/api-codegen/src/rest/schemaEmitter.ts @@ -0,0 +1,176 @@ +import { CodegenError } from "../errors.js"; +import { normalizePath } from "./normalizePath.js"; +import type { RestSpecConfig } from "../manifest.js"; + +const REST_METHODS = [ + "get", + "post", + "put", + "delete", + "patch", + "options", + "head", +] as const; + +type SpecOperation = { + operationId?: string; + requestBody?: { content?: Record }; + responses?: Record }>; + parameters?: Array<{ in?: string }>; +}; + +type LocatedOperation = { + path: string; + method: (typeof REST_METHODS)[number]; + operation: SpecOperation; +}; + +/** + * Finds an operation by operationId across all paths/methods of a bundled + * OpenAPI spec. + * + * @param {Record} spec The parsed OpenAPI snapshot + * @param {string} operationId The operationId to locate + * @returns {LocatedOperation} The operation with its path and method + */ +function locateOperation( + spec: Record, + operationId: string, +): LocatedOperation { + const paths = (spec.paths ?? {}) as Record< + string, + Record + >; + for (const [path, methods] of Object.entries(paths)) { + for (const method of REST_METHODS) { + const operation = methods[method]; + if (operation?.operationId === operationId) { + return { path, method, operation }; + } + } + } + // validateRestManifest runs first, so this indicates a walker bug. + throw new CodegenError(`Operation "${operationId}" not found in spec.`); +} + +/** + * Picks the success response status key for an operation: "200" if present, + * otherwise the first 2xx key. + * + * @param {SpecOperation} operation The spec operation + * @param {string} operationId For error messages + * @returns {{ status: string; contentType: string }} Status code and content type to index with + */ +function pickSuccessResponse( + operation: SpecOperation, + operationId: string, +): { status: string; contentType: string } { + const responses = operation.responses ?? {}; + const status = + "200" in responses + ? "200" + : Object.keys(responses).find((key) => /^2\d\d$/.test(key)); + if (!status) { + throw new CodegenError( + `Operation "${operationId}" has no 2xx response in the spec.`, + ); + } + const content = responses[status]?.content ?? {}; + const contentType = + "application/json" in content + ? "application/json" + : Object.keys(content)[0]; + if (!contentType) { + throw new CodegenError( + `Operation "${operationId}" response ${status} has no content types.`, + ); + } + return { status, contentType }; +} + +/** + * Emits the .schema.ts source for a REST spec: named Body/Response + * (and optional Query) aliases indexed into the openapi-typescript output, + * plus the RestRequestSchema tuple consumed by AlchemyRestClient. + * + * @param {RestSpecConfig} config The manifest entry for this spec + * @param {Record} spec The parsed OpenAPI snapshot + * @returns {string} TypeScript source (unformatted, no banner) + */ +export function emitRestSchema( + config: RestSpecConfig, + spec: Record, +): string { + const aliasBlocks: string[] = []; + const tupleEntries: string[] = []; + + for (const opConfig of config.operations) { + const { operationId, exportBaseName, emitQueryType } = opConfig; + const { path, method, operation } = locateOperation(spec, operationId); + const route = normalizePath(path, config.pathRules); + const hasBody = operation.requestBody != null; + const { status, contentType } = pickSuccessResponse(operation, operationId); + const opIndex = JSON.stringify(operationId); + + if (hasBody) { + const bodyContentType = Object.keys( + operation.requestBody?.content ?? {}, + ).includes("application/json") + ? "application/json" + : Object.keys(operation.requestBody?.content ?? {})[0]; + aliasBlocks.push( + `/** Request body for ${operationId}. */\n` + + `export type ${exportBaseName}Body = NonNullable<\n` + + ` operations[${opIndex}]["requestBody"]\n` + + `>["content"][${JSON.stringify(bodyContentType)}];`, + ); + } + + aliasBlocks.push( + `/** ${status} response for ${operationId}. */\n` + + `export type ${exportBaseName}Response =\n` + + ` operations[${opIndex}]["responses"][${JSON.stringify(status)}]["content"][${JSON.stringify(contentType)}];`, + ); + + if (emitQueryType) { + aliasBlocks.push( + `/**\n` + + ` * Query params for ${operationId}. Sent via the URL at runtime;\n` + + ` * RestRequestSchema has no query channel, so this is exposed as a\n` + + ` * standalone type for the SDK's params layer.\n` + + ` */\n` + + `export type ${exportBaseName}Query = NonNullable<\n` + + ` operations[${opIndex}]["parameters"]["query"]\n` + + `>;`, + ); + } + + tupleEntries.push( + ` {\n` + + ` /** ${method.toUpperCase()} ${path} (operationId: ${operationId}) */\n` + + ` Route: ${JSON.stringify(route)};\n` + + ` Method: ${JSON.stringify(method.toUpperCase())};\n` + + (hasBody + ? ` Body: ${exportBaseName}Body;\n` + : ` Body?: undefined;\n`) + + ` Response: ${exportBaseName}Response;\n` + + ` },`, + ); + } + + return [ + `import type { RestRequestSchema } from "@alchemy/common";`, + `import type { operations } from "./${config.spec}.types.js";`, + ``, + ...aliasBlocks.map((block) => block + "\n"), + `/** RestRequestSchema entries for the ${config.spec} REST API. */`, + `export type ${config.schemaTypeName} = readonly [`, + ...tupleEntries, + `];`, + ``, + `/** Compile-time guard that the emitted tuple satisfies the shared constraint. */`, + `export type _Assert${config.schemaTypeName} =`, + ` ${config.schemaTypeName} extends RestRequestSchema ? true : never;`, + ``, + ].join("\n"); +} diff --git a/packages/api-codegen/src/rpc/openrpcWalker.ts b/packages/api-codegen/src/rpc/openrpcWalker.ts new file mode 100644 index 0000000000..481b8985cf --- /dev/null +++ b/packages/api-codegen/src/rpc/openrpcWalker.ts @@ -0,0 +1,89 @@ +import { CodegenError } from "../errors.js"; + +/** JSON Schema node (loose — specs are already dereferenced). */ +export type JsonSchema = Record; + +/** An OpenRPC method's extracted schemas, ready for type compilation. */ +export type ExtractedMethod = { + /** JSON-RPC method name (e.g. "alchemy_getAssetTransfers"). */ + name: string; + /** Positional params: name, JSON Schema, and OpenRPC `required` flag (defaults false). */ + params: Array<{ name: string; required: boolean; schema: JsonSchema }>; + /** Result JSON Schema. */ + result: JsonSchema; +}; + +/** + * Recursively closes object schemas: sets `additionalProperties: false` + * wherever it's unspecified so json-schema-to-typescript emits closed + * interfaces instead of `[k: string]: unknown` index signatures. Returns a + * deep copy; the input is not mutated. + * + * @param {unknown} node A JSON Schema node (or fragment) + * @returns {unknown} The closed copy + */ +export function closeObjectSchemas(node: unknown): unknown { + if (Array.isArray(node)) { + return node.map(closeObjectSchemas); + } + if (node === null || typeof node !== "object") { + return node; + } + const copy: Record = {}; + for (const [key, value] of Object.entries(node)) { + copy[key] = closeObjectSchemas(value); + } + const isObjectSchema = + copy.type === "object" || copy.properties !== undefined; + if (isObjectSchema && copy.additionalProperties === undefined) { + copy.additionalProperties = false; + } + return copy; +} + +/** + * Extracts a method's param and result schemas from a bundled (dereferenced) + * OpenRPC document, with object schemas closed for clean type compilation. + * + * @param {Record} spec The parsed OpenRPC snapshot + * @param {string} methodName The JSON-RPC method to extract + * @returns {ExtractedMethod} The extracted schemas + */ +export function extractMethod( + spec: Record, + methodName: string, +): ExtractedMethod { + const methods = (spec.methods ?? []) as Array<{ + name?: string; + params?: Array<{ name?: string; required?: boolean; schema?: JsonSchema }>; + result?: { schema?: JsonSchema }; + }>; + const method = methods.find((m) => m.name === methodName); + if (!method) { + // validateRpcManifest runs first, so this indicates a walker bug. + throw new CodegenError(`Method "${methodName}" not found in spec.`); + } + + const params = (method.params ?? []).map((param, index) => { + if (!param.schema) { + throw new CodegenError( + `Method "${methodName}" param ${param.name ?? index} has no schema.`, + ); + } + return { + name: param.name ?? `param${index}`, + required: param.required === true, + schema: closeObjectSchemas(param.schema) as JsonSchema, + }; + }); + + if (!method.result?.schema) { + throw new CodegenError(`Method "${methodName}" has no result schema.`); + } + + return { + name: methodName, + params, + result: closeObjectSchemas(method.result.schema) as JsonSchema, + }; +} diff --git a/packages/api-codegen/src/rpc/rpcEmitter.ts b/packages/api-codegen/src/rpc/rpcEmitter.ts new file mode 100644 index 0000000000..6ce21a2540 --- /dev/null +++ b/packages/api-codegen/src/rpc/rpcEmitter.ts @@ -0,0 +1,81 @@ +import { compile } from "json-schema-to-typescript"; +import { extractMethod } from "./openrpcWalker.js"; +import type { RpcSpecConfig } from "../manifest.js"; + +/** + * Converts a param name to PascalCase for type naming. + * + * @param {string} name The param name (e.g. "assetTransferParams") + * @returns {string} PascalCase form + */ +function pascal(name: string): string { + return name.charAt(0).toUpperCase() + name.slice(1); +} + +/** + * Emits the .ts source for an OpenRPC spec: per-method param/result + * types compiled from their JSON Schemas (json-schema-to-typescript), plus a + * viem-shaped RpcSchema tuple so `client.request()` is fully typed. + * + * @param {RpcSpecConfig} config The manifest entry for this spec + * @param {Record} spec The parsed OpenRPC snapshot + * @returns {Promise} TypeScript source (unformatted, no banner) + */ +export async function emitRpcSchema( + config: RpcSpecConfig, + spec: Record, +): Promise { + const typeBlocks: string[] = []; + const tupleEntries: string[] = []; + + for (const methodConfig of config.methods) { + const { method, exportBaseName } = methodConfig; + const extracted = extractMethod(spec, method); + + // Single-param methods get the plain "Params" name; multi-param + // methods are disambiguated by param name. + const paramTupleMembers: string[] = []; + for (const param of extracted.params) { + const typeName = + extracted.params.length === 1 + ? `${exportBaseName}Params` + : `${exportBaseName}${pascal(param.name)}Param`; + const compiled = await compile( + // json-schema-to-typescript names the root type from `title` when + // present; pin the name we reference in the tuple instead. + { ...param.schema, title: typeName }, + typeName, + { bannerComment: "", format: false }, + ); + typeBlocks.push(compiled.trimEnd()); + paramTupleMembers.push( + `${param.name}${param.required ? "" : "?"}: ${typeName}`, + ); + } + + const resultTypeName = `${exportBaseName}Result`; + const compiledResult = await compile( + { ...extracted.result, title: resultTypeName }, + resultTypeName, + { bannerComment: "", format: false }, + ); + typeBlocks.push(compiledResult.trimEnd()); + + tupleEntries.push( + ` {\n` + + ` Method: ${JSON.stringify(method)};\n` + + ` Parameters: [${paramTupleMembers.join(", ")}];\n` + + ` ReturnType: ${resultTypeName};\n` + + ` },`, + ); + } + + return [ + ...typeBlocks.map((block) => block + "\n"), + `/** viem RpcSchema entries for the ${config.spec} JSON-RPC methods. */`, + `export type ${config.schemaTypeName} = [`, + ...tupleEntries, + `];`, + ``, + ].join("\n"); +} diff --git a/packages/api-codegen/src/snapshot.ts b/packages/api-codegen/src/snapshot.ts new file mode 100644 index 0000000000..01a25842f6 --- /dev/null +++ b/packages/api-codegen/src/snapshot.ts @@ -0,0 +1,194 @@ +import { execFileSync } from "node:child_process"; +import { existsSync, readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { CodegenError } from "./errors.js"; +import { sha256 } from "./hash.js"; +import { loadManifest } from "./manifest.js"; +import { LOCKFILE_PATH, REPO_ROOT, SPECS_DIR } from "./paths.js"; +import { TARGETS } from "./targets.js"; +import { writeIfChanged } from "./write.js"; + +/** The shape of specs.lock.json: docs provenance + per-snapshot checksums. */ +export type SpecsLockfile = { + docs: { repository: string; sha: string; branch: string }; + specs: Record; +}; + +type SnapshotOptions = { + /** Local docs checkout. Falls back to ALCHEMY_DOCS_DIR, then ../docs next to the repo. */ + docsDir?: string; + /** Skip the clean-working-tree requirement on the docs checkout. */ + allowDirty?: boolean; +}; + +/** + * Runs a git command in the docs checkout and returns trimmed stdout. + * + * @param {string} docsDir The docs checkout directory + * @param {string[]} args git arguments + * @returns {string} Trimmed stdout + */ +function git(docsDir: string, args: string[]): string { + return execFileSync("git", ["-C", docsDir, ...args], { + encoding: "utf8", + }).trim(); +} + +/** + * Collects the union of spec names (by channel) referenced by all registered + * targets' manifests — the single source of truth for what gets snapshotted. + * + * @returns {Promise<{ rest: string[]; rpc: string[] }>} Spec basenames per channel + */ +async function collectSpecNames(): Promise<{ rest: string[]; rpc: string[] }> { + const rest = new Set(); + const rpc = new Set(); + for (const target of Object.values(TARGETS)) { + const manifest = await loadManifest( + resolve(REPO_ROOT, target.packageDir, target.manifestPath), + ); + for (const entry of manifest.rest) rest.add(entry.spec); + for (const entry of manifest.rpc) rpc.add(entry.spec); + } + return { rest: [...rest].sort(), rpc: [...rpc].sort() }; +} + +/** + * Snapshots bundled specs from a local docs checkout into specs/ and writes + * specs.lock.json. Bundling uses the docs repo's own tooling: redocly per + * OpenAPI spec (mirroring its generate-open-api.sh invocation) and its + * generate:rpc script for OpenRPC. + * + * @param {SnapshotOptions} options Docs checkout location and dirty-tree override + */ +export async function snapshot(options: SnapshotOptions = {}): Promise { + const docsDir = resolve( + options.docsDir ?? + process.env.ALCHEMY_DOCS_DIR ?? + resolve(REPO_ROOT, "../docs"), + ); + if (!existsSync(resolve(docsDir, "package.json"))) { + throw new CodegenError( + `No docs checkout at ${docsDir}. Pass --docs or set ALCHEMY_DOCS_DIR.`, + ); + } + + const status = git(docsDir, ["status", "--porcelain"]); + if (status !== "" && !options.allowDirty) { + throw new CodegenError( + `Docs checkout at ${docsDir} has uncommitted changes; commit/stash them or pass --allow-dirty.\n${status}`, + ); + } + const sha = git(docsDir, ["rev-parse", "HEAD"]); + const branch = git(docsDir, ["rev-parse", "--abbrev-ref", "HEAD"]); + + const { rest, rpc } = await collectSpecNames(); + console.log( + `Snapshotting from docs@${sha.slice(0, 9)} (${branch}): rest=[${rest.join(", ")}] rpc=[${rpc.join(", ")}]`, + ); + + // REST: bundle each spec with the same redocly invocation the docs repo's + // generate-open-api.sh uses (skipping its remote-spec fetches and lint pass). + for (const name of rest) { + execFileSync( + "pnpm", + [ + "exec", + "redocly", + "bundle", + `src/openapi/${name}/${name}.yaml`, + "--dereferenced", + "--output", + `content/api-specs/alchemy/rest/${name}.json`, + "--ext", + "json", + "--remove-unused-components", + ], + { cwd: docsDir, stdio: "inherit" }, + ); + } + + // OpenRPC: the docs script generates all RPC specs in one pass (offline). + if (rpc.length > 0) { + execFileSync("pnpm", ["run", "generate:rpc"], { + cwd: docsDir, + stdio: "inherit", + }); + } + + const checksums: Record = {}; + const copies: Array<{ name: string; sourcePath: string }> = [ + ...rest.map((name) => ({ + name, + sourcePath: resolve( + docsDir, + `content/api-specs/alchemy/rest/${name}.json`, + ), + })), + ...rpc.map((name) => ({ + name, + sourcePath: resolve( + docsDir, + `content/api-specs/alchemy/json-rpc/${name}.json`, + ), + })), + ]; + for (const { name, sourcePath } of copies.sort((a, b) => + a.name.localeCompare(b.name), + )) { + if (!existsSync(sourcePath)) { + throw new CodegenError(`Expected bundled spec at ${sourcePath}.`); + } + // Normalize through a single stringify so snapshot formatting never + // depends on the docs tooling's serializer. + const normalized = + JSON.stringify(JSON.parse(readFileSync(sourcePath, "utf8")), null, 2) + + "\n"; + const snapshotPath = resolve(SPECS_DIR, `${name}.json`); + const wrote = writeIfChanged(snapshotPath, normalized); + checksums[`${name}.json`] = sha256(normalized); + console.log(` specs/${name}.json ${wrote ? "updated" : "unchanged"}`); + } + + const lockfile: SpecsLockfile = { + docs: { repository: "alchemyplatform/docs", sha, branch }, + specs: checksums, + }; + const wroteLock = writeIfChanged( + LOCKFILE_PATH, + JSON.stringify(lockfile, null, 2) + "\n", + ); + console.log(` specs/specs.lock.json ${wroteLock ? "updated" : "unchanged"}`); +} + +/** + * Reads a committed spec snapshot, verifying its checksum against the + * lockfile. Generate-time guard against hand-edited snapshots. + * + * @param {string} name Spec basename without extension + * @returns {Record} The parsed spec + */ +export function readSnapshot(name: string): Record { + const snapshotPath = resolve(SPECS_DIR, `${name}.json`); + if (!existsSync(snapshotPath)) { + throw new CodegenError( + `Missing spec snapshot specs/${name}.json — run \`pnpm --filter @alchemy/api-codegen snapshot\`.`, + ); + } + const content = readFileSync(snapshotPath, "utf8"); + const lockfile = JSON.parse( + readFileSync(LOCKFILE_PATH, "utf8"), + ) as SpecsLockfile; + const expected = lockfile.specs[`${name}.json`]; + if (!expected) { + throw new CodegenError( + `specs/${name}.json is not in specs.lock.json — re-run snapshot.`, + ); + } + if (sha256(content) !== expected) { + throw new CodegenError( + `Checksum mismatch for specs/${name}.json — the snapshot was modified outside the snapshot command. Re-run snapshot.`, + ); + } + return JSON.parse(content) as Record; +} diff --git a/packages/api-codegen/src/targets.ts b/packages/api-codegen/src/targets.ts new file mode 100644 index 0000000000..d2f50121d6 --- /dev/null +++ b/packages/api-codegen/src/targets.ts @@ -0,0 +1,18 @@ +/** A consuming package wired into the codegen pipeline. */ +export type TargetConfig = { + /** Package directory, relative to the repo root. */ + packageDir: string; + /** Manifest module path, relative to the package directory. */ + manifestPath: string; + /** Generated-output directory, relative to the package directory. */ + outputDir: string; +}; + +/** All registered codegen targets, keyed by `--target` name. */ +export const TARGETS: Record = { + "data-apis": { + packageDir: "packages/data-apis", + manifestPath: "codegen.manifest.ts", + outputDir: "src/generated", + }, +}; diff --git a/packages/api-codegen/src/write.ts b/packages/api-codegen/src/write.ts new file mode 100644 index 0000000000..83e8337699 --- /dev/null +++ b/packages/api-codegen/src/write.ts @@ -0,0 +1,20 @@ +import { mkdirSync, readFileSync, writeFileSync, existsSync } from "node:fs"; +import { dirname } from "node:path"; + +/** + * Writes a file only if its content actually changed, creating parent + * directories as needed. Keeps git status and build caches quiet when + * regeneration produces identical output. + * + * @param {string} filePath Absolute path to write + * @param {string} content File content + * @returns {boolean} true if the file was written, false if it was already up to date + */ +export function writeIfChanged(filePath: string, content: string): boolean { + if (existsSync(filePath) && readFileSync(filePath, "utf8") === content) { + return false; + } + mkdirSync(dirname(filePath), { recursive: true }); + writeFileSync(filePath, content); + return true; +} diff --git a/packages/api-codegen/tests/fixtures/rest.fixture.json b/packages/api-codegen/tests/fixtures/rest.fixture.json new file mode 100644 index 0000000000..13550b6960 --- /dev/null +++ b/packages/api-codegen/tests/fixtures/rest.fixture.json @@ -0,0 +1,82 @@ +{ + "openapi": "3.1.0", + "info": { "title": "Fixture REST API", "version": "1.0" }, + "paths": { + "/{apiKey}/foo/create": { + "post": { + "operationId": "create-foo", + "parameters": [ + { + "name": "apiKey", + "in": "path", + "required": true, + "schema": { "type": "string" } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["name"], + "properties": { "name": { "type": "string" } } + } + } + } + }, + "responses": { + "200": { + "description": "ok", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "id": { "type": "string" } } + } + } + } + } + } + } + }, + "/v3/{apiKey}/getBar": { + "get": { + "operationId": "getBar-v3", + "parameters": [ + { + "name": "apiKey", + "in": "path", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "owner", + "in": "query", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "tags[]", + "in": "query", + "schema": { "type": "array", "items": { "type": "string" } } + } + ], + "responses": { + "200": { + "description": "ok", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { "type": "array", "items": { "type": "string" } } + } + } + } + } + } + } + } + } + } +} diff --git a/packages/api-codegen/tests/fixtures/rpc.fixture.json b/packages/api-codegen/tests/fixtures/rpc.fixture.json new file mode 100644 index 0000000000..6b43396ecc --- /dev/null +++ b/packages/api-codegen/tests/fixtures/rpc.fixture.json @@ -0,0 +1,43 @@ +{ + "openrpc": "1.2.4", + "info": { "title": "Fixture RPC API", "version": "1.0" }, + "methods": [ + { + "name": "fixture_getThings", + "params": [ + { + "name": "thingParams", + "required": true, + "schema": { + "type": "object", + "properties": { + "kind": { "type": "string", "enum": ["a", "b"] }, + "limit": { "type": "string" } + } + } + } + ], + "result": { + "name": "things", + "schema": { + "oneOf": [ + { "title": "Not Found (null)", "type": "string" }, + { + "type": "object", + "properties": { + "pageKey": { "type": "string" }, + "things": { + "type": "array", + "items": { + "type": "object", + "properties": { "id": { "type": "string" } } + } + } + } + } + ] + } + } + } + ] +} diff --git a/packages/api-codegen/tests/manifest.test.ts b/packages/api-codegen/tests/manifest.test.ts new file mode 100644 index 0000000000..6a48a8daf2 --- /dev/null +++ b/packages/api-codegen/tests/manifest.test.ts @@ -0,0 +1,71 @@ +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { describe, expect, it } from "vitest"; +import { validateRestManifest, validateRpcManifest } from "../src/manifest.js"; + +const restSpec = JSON.parse( + readFileSync(resolve(__dirname, "fixtures/rest.fixture.json"), "utf8"), +); +const rpcSpec = JSON.parse( + readFileSync(resolve(__dirname, "fixtures/rpc.fixture.json"), "utf8"), +); + +describe("validateRestManifest", () => { + it("passes when all operationIds exist and reports uncovered operations", () => { + const uncovered = validateRestManifest( + { + spec: "rest.fixture", + schemaTypeName: "FooRestSchema", + operations: [ + { operationId: "create-foo", exportBaseName: "CreateFoo" }, + ], + }, + restSpec, + ); + expect(uncovered).toEqual(["getBar-v3"]); + }); + + it("hard-errors on a missing operationId, naming it", () => { + expect(() => + validateRestManifest( + { + spec: "rest.fixture", + schemaTypeName: "FooRestSchema", + operations: [ + { operationId: "create-foo-RENAMED", exportBaseName: "CreateFoo" }, + ], + }, + restSpec, + ), + ).toThrow(/create-foo-RENAMED/); + }); +}); + +describe("validateRpcManifest", () => { + it("passes when all methods exist", () => { + const uncovered = validateRpcManifest( + { + spec: "rpc.fixture", + schemaTypeName: "FixtureRpcSchema", + methods: [{ method: "fixture_getThings", exportBaseName: "GetThings" }], + }, + rpcSpec, + ); + expect(uncovered).toEqual([]); + }); + + it("hard-errors on a missing method, naming it", () => { + expect(() => + validateRpcManifest( + { + spec: "rpc.fixture", + schemaTypeName: "FixtureRpcSchema", + methods: [ + { method: "fixture_getThingsGone", exportBaseName: "GetThings" }, + ], + }, + rpcSpec, + ), + ).toThrow(/fixture_getThingsGone/); + }); +}); diff --git a/packages/api-codegen/tests/normalizePath.test.ts b/packages/api-codegen/tests/normalizePath.test.ts new file mode 100644 index 0000000000..0d48a97efc --- /dev/null +++ b/packages/api-codegen/tests/normalizePath.test.ts @@ -0,0 +1,42 @@ +import { describe, expect, it } from "vitest"; +import { normalizePath } from "../src/rest/normalizePath.js"; +import { CodegenError } from "../src/errors.js"; + +describe("normalizePath", () => { + it("strips {apiKey} segments and leading slash", () => { + expect( + normalizePath("/{apiKey}/assets/tokens/by-address", { + stripApiKeySegment: true, + }), + ).toBe("assets/tokens/by-address"); + }); + + it("strips a configured prefix after the apiKey segment", () => { + expect( + normalizePath("/v3/{apiKey}/getNFTsForOwner", { + stripApiKeySegment: true, + stripPrefix: "/v3", + }), + ).toBe("getNFTsForOwner"); + }); + + it("strips {apiKey} by default", () => { + expect(normalizePath("/{apiKey}/foo")).toBe("foo"); + }); + + it("preserves other path params", () => { + expect(normalizePath("/{apiKey}/contracts/{address}")).toBe( + "contracts/{address}", + ); + }); + + it("errors when the configured prefix does not match", () => { + expect(() => + normalizePath("/v4/{apiKey}/getNFTsForOwner", { stripPrefix: "/v3" }), + ).toThrow(CodegenError); + }); + + it("errors when normalization produces an empty route", () => { + expect(() => normalizePath("/{apiKey}")).toThrow(CodegenError); + }); +}); diff --git a/packages/api-codegen/tests/rpcEmitter.test.ts b/packages/api-codegen/tests/rpcEmitter.test.ts new file mode 100644 index 0000000000..1459b723e0 --- /dev/null +++ b/packages/api-codegen/tests/rpcEmitter.test.ts @@ -0,0 +1,56 @@ +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { describe, expect, it } from "vitest"; +import { emitRpcSchema } from "../src/rpc/rpcEmitter.js"; +import { closeObjectSchemas } from "../src/rpc/openrpcWalker.js"; + +const spec = JSON.parse( + readFileSync(resolve(__dirname, "fixtures/rpc.fixture.json"), "utf8"), +); + +describe("closeObjectSchemas", () => { + it("sets additionalProperties: false on object schemas that omit it", () => { + const closed = closeObjectSchemas({ + type: "object", + properties: { nested: { type: "object", properties: {} } }, + }) as Record; + expect(closed.additionalProperties).toBe(false); + expect(closed.properties.nested.additionalProperties).toBe(false); + }); + + it("does not override an explicit additionalProperties", () => { + const closed = closeObjectSchemas({ + type: "object", + additionalProperties: true, + }) as Record; + expect(closed.additionalProperties).toBe(true); + }); +}); + +describe("emitRpcSchema", () => { + it("compiles params/result types and emits the RpcSchema tuple", async () => { + const source = await emitRpcSchema( + { + spec: "rpc.fixture", + schemaTypeName: "FixtureRpcSchema", + methods: [ + { method: "fixture_getThings", exportBaseName: "FixtureGetThings" }, + ], + }, + spec, + ); + // single param → plain Params name; required → no optional marker + expect(source).toContain("export interface FixtureGetThingsParams"); + // raw j2ts output (prettier formatting happens at emit time) + expect(source).toContain(`kind?: ("a" | "b")`); + // oneOf(string-titled, object) result compiles to a union + expect(source).toContain("export type FixtureGetThingsResult"); + // no index signatures leak from open object schemas + expect(source).not.toContain("[k: string]"); + expect(source).toContain(`Method: "fixture_getThings";`); + expect(source).toContain( + "Parameters: [thingParams: FixtureGetThingsParams];", + ); + expect(source).toContain("ReturnType: FixtureGetThingsResult;"); + }); +}); diff --git a/packages/api-codegen/tests/schemaEmitter.test.ts b/packages/api-codegen/tests/schemaEmitter.test.ts new file mode 100644 index 0000000000..45d15daa93 --- /dev/null +++ b/packages/api-codegen/tests/schemaEmitter.test.ts @@ -0,0 +1,59 @@ +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { describe, expect, it } from "vitest"; +import { emitRestSchema } from "../src/rest/schemaEmitter.js"; + +const spec = JSON.parse( + readFileSync(resolve(__dirname, "fixtures/rest.fixture.json"), "utf8"), +); + +describe("emitRestSchema", () => { + it("emits Body/Response aliases and a schema tuple for a POST operation", () => { + const source = emitRestSchema( + { + spec: "rest.fixture", + schemaTypeName: "FooRestSchema", + pathRules: { stripApiKeySegment: true }, + operations: [ + { operationId: "create-foo", exportBaseName: "CreateFoo" }, + ], + }, + spec, + ); + expect(source).toContain( + `import type { operations } from "./rest.fixture.types.js";`, + ); + expect(source).toContain( + `export type CreateFooBody = NonNullable<\n operations["create-foo"]["requestBody"]\n>["content"]["application/json"];`, + ); + expect(source).toContain(`Route: "foo/create";`); + expect(source).toContain(`Method: "POST";`); + expect(source).toContain(`Body: CreateFooBody;`); + expect(source).toContain( + `FooRestSchema extends RestRequestSchema ? true : never;`, + ); + }); + + it("emits a query type and bodyless tuple entry for a GET operation", () => { + const source = emitRestSchema( + { + spec: "rest.fixture", + schemaTypeName: "BarRestSchema", + pathRules: { stripApiKeySegment: true, stripPrefix: "/v3" }, + operations: [ + { + operationId: "getBar-v3", + exportBaseName: "GetBar", + emitQueryType: true, + }, + ], + }, + spec, + ); + expect(source).toContain( + `export type GetBarQuery = NonNullable<\n operations["getBar-v3"]["parameters"]["query"]\n>;`, + ); + expect(source).toContain(`Route: "getBar";`); + expect(source).toContain(`Body?: undefined;`); + }); +}); diff --git a/packages/api-codegen/tsconfig.json b/packages/api-codegen/tsconfig.json new file mode 100644 index 0000000000..e171f89cba --- /dev/null +++ b/packages/api-codegen/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "typescript-template/base.json", + "compilerOptions": { + "types": ["node"] + }, + "include": ["src", "tests"] +} diff --git a/packages/api-codegen/vitest.config.ts b/packages/api-codegen/vitest.config.ts new file mode 100644 index 0000000000..2626bc221c --- /dev/null +++ b/packages/api-codegen/vitest.config.ts @@ -0,0 +1,13 @@ +import { defineProject } from "vitest/config"; + +export default defineProject({ + test: { + name: "alchemy/api-codegen", + globals: true, + include: ["tests/**/*.test.ts"], + setupFiles: [], + globalSetup: undefined, + testTimeout: 30_000, + hookTimeout: 30_000, + }, +}); diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index ef3322c49e..2d927a9751 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -2,10 +2,10 @@ export type * from "./transport/alchemy.js"; export { alchemyTransport, isAlchemyTransport } from "./transport/alchemy.js"; -// http -- Revisit exporting this once it has a use case. -// export type * from "./rest/restClient.js"; -// export type * from "./rest/types.js"; -// export { AlchemyRestClient } from "./rest/restClient.js"; +// http -- exported for @alchemy/data-apis (REST channel); hardening tracked in the data SDK plan +export type * from "./rest/restClient.js"; +export type * from "./rest/types.js"; +export { AlchemyRestClient } from "./rest/restClient.js"; // chain registry utilities export { @@ -14,6 +14,15 @@ export { getSupportedChainIds, } from "./transport/chainRegistry.js"; +// network registry (slug / CAIP-2 / viem Chain resolution) +export type { + KnownAlchemyNetwork, + AlchemyNetwork, + NetworkInput, + ResolvedNetwork, +} from "./networks/networkRegistry.js"; +export { resolveNetwork } from "./networks/networkRegistry.js"; + // utils export type * from "./utils/types.js"; export { assertNever } from "./utils/assertNever.js"; diff --git a/packages/common/src/networks/networkRegistry.ts b/packages/common/src/networks/networkRegistry.ts new file mode 100644 index 0000000000..1c5f7b887c --- /dev/null +++ b/packages/common/src/networks/networkRegistry.ts @@ -0,0 +1,138 @@ +import type { Chain } from "viem"; +import { BaseError } from "../errors/BaseError.js"; +import { ALCHEMY_RPC_MAPPING } from "../transport/chainRegistry.js"; + +/** + * Known Alchemy network slugs for autocomplete. + * + * TODO(data-sdk): generate this union from daikon via the ws-tools CLI in the + * same pass that generates ALCHEMY_RPC_MAPPING, so it is never hand-maintained. + * This subset exists to prove the MVP only. + */ +export type KnownAlchemyNetwork = + | "eth-mainnet" + | "eth-sepolia" + | "base-mainnet" + | "base-sepolia" + | "polygon-mainnet" + | "polygon-amoy" + | "arb-mainnet" + | "arb-sepolia" + | "opt-mainnet" + | "opt-sepolia" + | "solana-mainnet" + | "solana-devnet"; + +/** + * An Alchemy network identifier. Known slugs get autocomplete; arbitrary + * strings are accepted as an escape hatch so new networks work without an + * SDK release. + */ +export type AlchemyNetwork = KnownAlchemyNetwork | (string & {}); + +/** + * Any accepted network input: a viem Chain, an Alchemy network slug + * (e.g. "eth-mainnet"), or a CAIP-2 identifier (e.g. "eip155:1", + * "solana:mainnet"). + */ +export type NetworkInput = Chain | AlchemyNetwork; + +/** + * A resolved network: the Alchemy slug used for URL construction and REST + * payloads, plus the numeric chain ID when one exists (EVM only). + */ +export type ResolvedNetwork = { + slug: string; + chainId?: number; +}; + +// Solana networks have no numeric chain ID; CAIP-2 aliases match the +// identifiers wallet-apis already uses. +const SOLANA_SLUG_BY_CAIP2: Record = { + "solana:mainnet": "solana-mainnet", + "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": "solana-mainnet", + "solana:devnet": "solana-devnet", + "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": "solana-devnet", +}; + +const SOLANA_SLUGS = new Set(Object.values(SOLANA_SLUG_BY_CAIP2)); + +const SLUG_PATTERN = /^[a-z0-9-]+$/; + +// The slug is already present in every daikon-generated registry URL +// (https://{slug}.g.alchemy.com/v2); derive the slug<->chainId maps from it +// rather than maintaining a second copy. Once ws-tools emits structured +// entries ({ slug, chainId, caip2 }), these derivations go away. +const slugByChainId = new Map(); +const chainIdBySlug = new Map(); +for (const [chainId, url] of Object.entries(ALCHEMY_RPC_MAPPING)) { + const slug = new URL(url).hostname.split(".")[0]; + if (slug) { + slugByChainId.set(Number(chainId), slug); + chainIdBySlug.set(slug, Number(chainId)); + } +} + +/** + * Resolves any accepted network input — viem Chain, Alchemy network slug, or + * CAIP-2 identifier — to the Alchemy network slug (and chain ID when one + * exists). All three forms resolve against the same daikon-generated registry. + * + * @example + * ```ts + * import { mainnet } from "viem/chains"; + * resolveNetwork(mainnet); // { slug: "eth-mainnet", chainId: 1 } + * resolveNetwork("eth-mainnet"); // { slug: "eth-mainnet", chainId: 1 } + * resolveNetwork("eip155:1"); // { slug: "eth-mainnet", chainId: 1 } + * resolveNetwork("solana:mainnet"); // { slug: "solana-mainnet" } + * ``` + * + * @param {NetworkInput} input The network to resolve + * @returns {ResolvedNetwork} The resolved slug and optional chain ID + */ +export function resolveNetwork(input: NetworkInput): ResolvedNetwork { + if (typeof input === "object") { + const slug = slugByChainId.get(input.id); + if (!slug) { + throw new BaseError( + `Chain ${input.id} (${input.name}) is not in the Alchemy network registry. ` + + `Pass an Alchemy network slug (e.g. "eth-mainnet") instead.`, + ); + } + return { slug, chainId: input.id }; + } + + if (input.startsWith("eip155:")) { + const chainId = Number(input.slice("eip155:".length)); + const slug = slugByChainId.get(chainId); + if (!Number.isInteger(chainId) || !slug) { + throw new BaseError( + `CAIP-2 identifier "${input}" is not in the Alchemy network registry.`, + ); + } + return { slug, chainId }; + } + + if (input.startsWith("solana:")) { + const slug = SOLANA_SLUG_BY_CAIP2[input]; + if (!slug) { + throw new BaseError( + `CAIP-2 identifier "${input}" is not a known Solana network.`, + ); + } + return { slug }; + } + + if (!SLUG_PATTERN.test(input)) { + throw new BaseError( + `"${input}" is not a valid Alchemy network slug (expected lowercase letters, digits, and hyphens).`, + ); + } + + // Known slugs resolve a chain ID; unknown slugs are the escape hatch for + // networks newer than the shipped registry (URL is composed directly). + if (SOLANA_SLUGS.has(input)) { + return { slug: input }; + } + return { slug: input, chainId: chainIdBySlug.get(input) }; +} diff --git a/packages/common/tests/networks/networkRegistry.test.ts b/packages/common/tests/networks/networkRegistry.test.ts new file mode 100644 index 0000000000..b899d4801e --- /dev/null +++ b/packages/common/tests/networks/networkRegistry.test.ts @@ -0,0 +1,58 @@ +import { mainnet, arbitrumSepolia } from "viem/chains"; +import { describe, expect, it } from "vitest"; +import { resolveNetwork } from "../../src/networks/networkRegistry.js"; + +describe("resolveNetwork", () => { + it("resolves a viem chain via the registry", () => { + expect(resolveNetwork(mainnet)).toEqual({ + slug: "eth-mainnet", + chainId: 1, + }); + expect(resolveNetwork(arbitrumSepolia)).toEqual({ + slug: "arb-sepolia", + chainId: 421614, + }); + }); + + it("resolves a known slug to the same entry as the chain", () => { + expect(resolveNetwork("eth-mainnet")).toEqual(resolveNetwork(mainnet)); + }); + + it("resolves CAIP-2 identifiers", () => { + expect(resolveNetwork("eip155:1")).toEqual({ + slug: "eth-mainnet", + chainId: 1, + }); + expect(resolveNetwork("solana:mainnet")).toEqual({ + slug: "solana-mainnet", + }); + expect(resolveNetwork("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp")).toEqual({ + slug: "solana-mainnet", + }); + }); + + it("passes through unknown slugs as the escape hatch", () => { + expect(resolveNetwork("some-new-chain")).toEqual({ + slug: "some-new-chain", + chainId: undefined, + }); + }); + + it("rejects inputs that are not valid hostname labels", () => { + expect(() => resolveNetwork("Not A Slug!")).toThrow(); + expect(() => resolveNetwork("eth-mainnet/../evil")).toThrow(); + }); + + it("rejects chains and CAIP-2 ids missing from the registry", () => { + expect(() => + resolveNetwork({ + id: 999999001, + name: "Unknown", + nativeCurrency: { name: "X", symbol: "X", decimals: 18 }, + rpcUrls: { default: { http: [] } }, + }), + ).toThrow(); + expect(() => resolveNetwork("eip155:999999001")).toThrow(); + expect(() => resolveNetwork("solana:unknownref")).toThrow(); + }); +}); diff --git a/packages/data-apis/README.md b/packages/data-apis/README.md new file mode 100644 index 0000000000..cd7b4c5a69 --- /dev/null +++ b/packages/data-apis/README.md @@ -0,0 +1,56 @@ +# @alchemy/data-apis (MVP) + +A vertical-slice prototype of the Data APIs SDK, built to prove the architecture +before scaling to the full v1 surface (Portfolio, Prices, NFT, Token, Transfers). + +## What this proves + +One method per seam, not full coverage: + +| Method | Channel | What it demonstrates | +| ------------------------------ | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| `portfolio.getTokensByAddress` | REST → global `api.g.alchemy.com/data/v1` | Multi-network request bodies via `AlchemyRestClient`; networks are payload, the client's chain is not involved | +| `nft.getNftsForOwner` | REST → `{network}.g.alchemy.com/nft/v3` | Network-scoped endpoint resolution with per-request `network` override falling back to the client default | +| `transfers.getAssetTransfers` | JSON-RPC → `AlchemyTransport` | Plain viem action; network override derives a transport instance from `client.transport.config` | + +Plus the two entry points: + +```ts +// Data-only developers (no viem knowledge required) +const data = createDataClient({ apiKey, network: "eth-mainnet" }); + +// Developers already on a viem client with an Alchemy transport +const client = createClient({ + chain: mainnet, + transport: alchemyTransport({ apiKey }), +}).extend(dataActions); +``` + +Network inputs accept all three formats everywhere, resolved by +`resolveNetwork()` in `@alchemy/common`: a viem `Chain`, an Alchemy slug +(`"eth-mainnet"`), or CAIP-2 (`"eip155:1"`, `"solana:mainnet"`). The slug ↔ +chain-ID mapping is derived from the existing daikon-generated +`ALCHEMY_RPC_MAPPING` — no second registry. + +## Generated internals + +Param/result types are generated from the docs repo's bundled OpenAPI/OpenRPC +specs by `@alchemy/api-codegen` (see that package's README for the +snapshot/generate pipeline). `src/generated/` is committed, machine-owned, and +never re-exported directly: the public types in `src/types.ts` are +hand-reviewed aliases, and `codegen.manifest.ts` maps spec operations to the +generated surface — referencing a renamed/removed spec operation fails +`pnpm generate` loudly. + +## Companion changes in @alchemy/common + +- `networks/networkRegistry.ts`: `resolveNetwork` + network types (slug map + derived from the registry URLs; to be emitted by ws-tools properly) +- `AlchemyRestClient` is now exported (was written for signer v5 but unexported) + +## Deliberately out of scope (tracked in the data SDK scope plan) + +- Rest client hardening: retries, timeouts, request-id, first-class query params +- Pagination iterators, error normalization, the SDK manifest, remaining methods +- ws-tools generator change to emit `{ slug, chainId, caip2 }` entries + + the `KnownAlchemyNetwork` union diff --git a/packages/data-apis/codegen.manifest.ts b/packages/data-apis/codegen.manifest.ts new file mode 100644 index 0000000000..ce041ddaaf --- /dev/null +++ b/packages/data-apis/codegen.manifest.ts @@ -0,0 +1,50 @@ +import type { CodegenManifest } from "@alchemy/api-codegen"; + +// The hand-maintained overlay mapping spec operations to this package's +// generated internals (src/generated/). Validated against the committed spec +// snapshots on every `pnpm generate` — referencing a renamed/removed spec +// operation is a hard error. Public naming and pagination semantics stay +// human decisions; everything type-shaped is generated. +export default { + rest: [ + { + spec: "portfolio", + schemaTypeName: "PortfolioRestSchema", + // Spec path: POST /{apiKey}/assets/tokens/by-address. Runtime auth is + // header-based against https://api.g.alchemy.com/data/v1. + pathRules: { stripApiKeySegment: true }, + operations: [ + { + operationId: "get-tokens-by-address", + exportBaseName: "GetTokensByAddress", + }, + ], + }, + { + spec: "nft", + schemaTypeName: "NftRestSchema", + // Spec path: GET /v3/{apiKey}/getNFTsForOwner. Runtime base URL is + // https://{network}.g.alchemy.com/nft/v3, so /v3 is stripped too. + pathRules: { stripApiKeySegment: true, stripPrefix: "/v3" }, + operations: [ + { + operationId: "getNFTsForOwner-v3", + exportBaseName: "GetNftsForOwner", + emitQueryType: true, + }, + ], + }, + ], + rpc: [ + { + spec: "transfers", + schemaTypeName: "TransfersRpcSchema", + methods: [ + { + method: "alchemy_getAssetTransfers", + exportBaseName: "AlchemyGetAssetTransfers", + }, + ], + }, + ], +} satisfies CodegenManifest; diff --git a/packages/data-apis/inject-version.ts b/packages/data-apis/inject-version.ts new file mode 100644 index 0000000000..05e1caae82 --- /dev/null +++ b/packages/data-apis/inject-version.ts @@ -0,0 +1,19 @@ +import { readFileSync, writeFileSync } from "fs"; +import { dirname, resolve } from "path"; +import { fileURLToPath } from "url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const VERSION_FILE_PATH = "src/version.ts"; + +const packageJSON = JSON.parse(readFileSync("./package.json").toString()); + +writeFileSync( + resolve(__dirname, VERSION_FILE_PATH), + `// This file is autogenerated by inject-version.ts. Any changes will be +// overwritten on commit! +export const VERSION = "${packageJSON.version}"; +`, +); +console.log(`Wrote version to ${VERSION_FILE_PATH}.`); diff --git a/packages/data-apis/package.json b/packages/data-apis/package.json new file mode 100644 index 0000000000..4cba0ec8cc --- /dev/null +++ b/packages/data-apis/package.json @@ -0,0 +1,66 @@ +{ + "name": "@alchemy/data-apis", + "version": "0.0.0", + "description": "Alchemy Data APIs SDK (Portfolio, Prices, NFT, Token, Transfers) — MVP", + "author": "Alchemy", + "license": "MIT", + "private": false, + "type": "module", + "main": "./dist/esm/index.js", + "module": "./dist/esm/index.js", + "types": "./dist/types/index.d.ts", + "typings": "./dist/types/index.d.ts", + "sideEffects": false, + "files": [ + "dist", + "src/**/*.ts", + "!dist/**/*.tsbuildinfo", + "!vitest.config.ts", + "!.env", + "!src/**/*.test.ts", + "!src/**/*.test-d.ts", + "!src/__tests__/**/*" + ], + "exports": { + ".": { + "types": "./dist/types/index.d.ts", + "import": "./dist/esm/index.js", + "default": "./dist/esm/index.js" + }, + "./package.json": "./package.json" + }, + "scripts": { + "prebuild": "tsx ./inject-version.ts", + "build": "pnpm run clean && pnpm run build:esm && pnpm run build:types", + "build:esm": "tsc --project tsconfig.build.json --outDir ./dist/esm", + "build:types": "tsc --project tsconfig.build.json --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap", + "clean": "rm -rf ./dist", + "generate": "tsx ../api-codegen/src/cli.ts --target data-apis", + "test": "vitest", + "test:run": "vitest run", + "smoke-test": "tsx scripts/smoke-test.ts" + }, + "devDependencies": { + "@alchemy/api-codegen": "workspace:*", + "typescript-template": "workspace:*", + "viem": "^2.45.0" + }, + "dependencies": { + "@alchemy/common": "workspace:*" + }, + "peerDependencies": { + "viem": "^2.45.0" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/alchemyplatform/aa-sdk.git" + }, + "bugs": { + "url": "https://github.com/alchemyplatform/aa-sdk/issues" + }, + "homepage": "https://github.com/alchemyplatform/aa-sdk#readme" +} diff --git a/packages/data-apis/scripts/smoke-test.ts b/packages/data-apis/scripts/smoke-test.ts new file mode 100644 index 0000000000..eb8fc81e75 --- /dev/null +++ b/packages/data-apis/scripts/smoke-test.ts @@ -0,0 +1,261 @@ +/** + * Smoke test for @alchemy/data-apis — runs against the real Alchemy API. + * + * Usage: + * ALCHEMY_API_KEY= pnpm --filter @alchemy/data-apis smoke-test + * + * What it covers: + * - createDataClient with slug, viem Chain, and CAIP-2 network inputs + * - portfolio.getTokensByAddress (REST, multi-network, all three input formats) + * - nft.getNftsForOwner (REST, per-network, per-request override) + * - transfers.getAssetTransfers (JSON-RPC, per-request network override) + */ + +import { mainnet } from "viem/chains"; +import { BaseError } from "@alchemy/common"; +import { createDataClient } from "../src/client.js"; +import { dataActions } from "../src/decorator.js"; +import { alchemyTransport } from "@alchemy/common"; +import { createClient } from "viem"; + +const API_KEY = process.env.ALCHEMY_API_KEY; +if (!API_KEY) { + console.error("ALCHEMY_API_KEY env var is required"); + process.exit(1); +} + +// Vitalik's address — publicly known, reliably has tokens, NFTs, and transfer history. +const VITALIK = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"; + +let passed = 0; +let failed = 0; + +async function test(name: string, fn: () => Promise) { + process.stdout.write(` ${name} ... `); + try { + await fn(); + console.log("\x1b[32mPASS\x1b[0m"); + passed++; + } catch (err) { + console.log("\x1b[31mFAIL\x1b[0m"); + console.error(` ${err instanceof Error ? err.message : String(err)}`); + failed++; + } +} + +function assert(condition: boolean, message: string) { + if (!condition) throw new BaseError(`Assertion failed: ${message}`); +} + +// ─── Clients ────────────────────────────────────────────────────────────────── + +// Three ways to specify the default network +const clientBySlug = createDataClient({ + apiKey: API_KEY, + network: "eth-mainnet", +}); +const clientByChain = createDataClient({ + apiKey: API_KEY, + network: mainnet, +}); +const clientByCaip2 = createDataClient({ + apiKey: API_KEY, + network: "eip155:1", +}); + +// Decorator path: bring-your-own viem client +const rawViemClient = createClient({ + chain: mainnet, + transport: alchemyTransport({ apiKey: API_KEY }), +}).extend(dataActions); + +// ─── Tests ──────────────────────────────────────────────────────────────────── + +console.log("\n\x1b[1mportfolio.getTokensByAddress\x1b[0m"); + +await test("single network (slug)", async () => { + const result = await clientBySlug.portfolio.getTokensByAddress({ + addresses: [{ address: VITALIK, networks: ["eth-mainnet"] }], + withMetadata: true, + includeNativeTokens: true, + }); + assert( + Array.isArray(result.data.tokens), + "result.data.tokens should be an array", + ); + assert((result.data.tokens ?? []).length > 0, "expected at least one token"); +}); + +await test("multi-network: viem Chain + slug + CAIP-2 in one call", async () => { + const result = await clientBySlug.portfolio.getTokensByAddress({ + addresses: [ + { + address: VITALIK, + networks: [ + mainnet, // viem Chain + "base-mainnet", // Alchemy slug + "eip155:137", // CAIP-2 (Polygon) + ], + }, + ], + withMetadata: false, + includeNativeTokens: true, + includeErc20Tokens: false, + }); + assert( + Array.isArray(result.data.tokens), + "result.data.tokens should be an array", + ); + // expect at least some native ETH/MATIC results across 3 networks + assert( + (result.data.tokens ?? []).length > 0, + "expected tokens across multiple networks", + ); +}); + +console.log("\n\x1b[1mnft.getNftsForOwner\x1b[0m"); + +await test("uses client-level network (slug)", async () => { + const result = await clientBySlug.nft.getNftsForOwner({ owner: VITALIK }); + assert( + typeof result.totalCount === "number", + "totalCount should be a number", + ); + assert( + (result.totalCount ?? 0) > 0, + "Vitalik should own some NFTs on mainnet", + ); +}); + +await test("uses client-level network (viem Chain)", async () => { + const result = await clientByChain.nft.getNftsForOwner({ owner: VITALIK }); + assert( + typeof result.totalCount === "number", + "totalCount should be a number", + ); +}); + +await test("uses client-level network (CAIP-2)", async () => { + const result = await clientByCaip2.nft.getNftsForOwner({ owner: VITALIK }); + assert( + typeof result.totalCount === "number", + "totalCount should be a number", + ); +}); + +await test("per-request network override (slug)", async () => { + // client defaults to mainnet but we override to base + const mainnetResult = await clientBySlug.nft.getNftsForOwner({ + owner: VITALIK, + }); + const baseResult = await clientBySlug.nft.getNftsForOwner({ + owner: VITALIK, + network: "base-mainnet", + }); + // Different chains — counts may differ (just verify both return valid shapes) + assert( + typeof mainnetResult.totalCount === "number", + "mainnet totalCount should be a number", + ); + assert( + typeof baseResult.totalCount === "number", + "base totalCount should be a number", + ); +}); + +await test("per-request network override (CAIP-2)", async () => { + const result = await clientBySlug.nft.getNftsForOwner({ + owner: VITALIK, + network: "eip155:1", + }); + assert( + typeof result.totalCount === "number", + "totalCount should be a number", + ); +}); + +await test("pageSize param", async () => { + const result = await clientBySlug.nft.getNftsForOwner({ + owner: VITALIK, + pageSize: 2, + withMetadata: false, + }); + assert((result.ownedNfts ?? []).length <= 2, "should respect pageSize=2"); +}); + +console.log("\n\x1b[1mtransfers.getAssetTransfers\x1b[0m"); + +await test("uses client-level network (slug)", async () => { + const result = await clientBySlug.transfers.getAssetTransfers({ + fromAddress: VITALIK, + category: ["external"], + maxCount: "0x5", + order: "desc", + withMetadata: true, + }); + assert(Array.isArray(result.transfers), "transfers should be an array"); + assert((result.transfers ?? []).length > 0, "expected at least one transfer"); +}); + +await test("uses client-level network (viem Chain)", async () => { + const result = await clientByChain.transfers.getAssetTransfers({ + fromAddress: VITALIK, + category: ["external"], + maxCount: "0x3", + }); + assert(Array.isArray(result.transfers), "transfers should be an array"); +}); + +await test("per-request network override (slug)", async () => { + const result = await clientBySlug.transfers.getAssetTransfers({ + fromAddress: VITALIK, + category: ["external", "erc20"], + network: "base-mainnet", + maxCount: "0x5", + }); + assert(Array.isArray(result.transfers), "transfers should be an array"); +}); + +await test("per-request network override (CAIP-2)", async () => { + const result = await clientBySlug.transfers.getAssetTransfers({ + fromAddress: VITALIK, + category: ["external"], + network: "eip155:137", // Polygon + maxCount: "0x3", + }); + assert(Array.isArray(result.transfers), "transfers should be an array"); +}); + +console.log("\n\x1b[1mdecorator path (raw viem client + dataActions)\x1b[0m"); + +await test("client.extend(dataActions) works identically", async () => { + const result = await rawViemClient.transfers.getAssetTransfers({ + fromAddress: VITALIK, + category: ["external"], + maxCount: "0x3", + order: "desc", + }); + assert(Array.isArray(result.transfers), "transfers should be an array"); +}); + +await test("nft via raw viem client", async () => { + const result = await rawViemClient.nft.getNftsForOwner({ + owner: VITALIK, + pageSize: 1, + }); + assert( + typeof result.totalCount === "number", + "totalCount should be a number", + ); +}); + +// ─── Summary ────────────────────────────────────────────────────────────────── + +console.log(`\n${"─".repeat(50)}`); +const total = passed + failed; +if (failed === 0) { + console.log(`\x1b[32m✓ All ${total} tests passed\x1b[0m`); +} else { + console.log(`\x1b[31m✗ ${failed}/${total} tests failed\x1b[0m`); + process.exit(1); +} diff --git a/packages/data-apis/src/actions/nft/getNftsForOwner.ts b/packages/data-apis/src/actions/nft/getNftsForOwner.ts new file mode 100644 index 0000000000..ad038ba464 --- /dev/null +++ b/packages/data-apis/src/actions/nft/getNftsForOwner.ts @@ -0,0 +1,44 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + GetNftsForOwnerParams, + GetNftsForOwnerResult, +} from "../../types.js"; + +/** + * Fetches NFTs owned by an address on a single network. The network is + * resolved per request: an explicit `network` param wins, otherwise the + * client's configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetNftsForOwnerParams} params Owner address, optional network override, and filters + * @returns {Promise} The owned NFTs and pagination cursor + */ +export async function getNftsForOwner( + client: DataClient, + params: GetNftsForOwnerParams, +): Promise { + const { network, owner, contractAddresses, ...rest } = params; + const { slug } = resolveRequestNetwork(client, network); + + const query = new URLSearchParams({ owner }); + for (const [key, value] of Object.entries(rest)) { + if (value != null) query.set(key, String(value)); + } + for (const address of contractAddresses ?? []) { + query.append("contractAddresses[]", address); + } + + const restClient = getRestClient(client, getNftApiUrl(slug)); + // TODO(common-hardening): AlchemyRestClient should take query params + // first-class instead of this cast; tracked in the data SDK plan. + return restClient.request({ + route: `getNFTsForOwner?${query.toString()}` as "getNFTsForOwner", + method: "GET", + }); +} diff --git a/packages/data-apis/src/actions/portfolio/getTokensByAddress.ts b/packages/data-apis/src/actions/portfolio/getTokensByAddress.ts new file mode 100644 index 0000000000..dde71c5bb0 --- /dev/null +++ b/packages/data-apis/src/actions/portfolio/getTokensByAddress.ts @@ -0,0 +1,49 @@ +import { resolveNetwork } from "@alchemy/common"; +import { DATA_API_URL } from "../../internal/endpoints.js"; +import { + getRestClient, + type DataClient, +} from "../../internal/clientHelpers.js"; +import type { PortfolioRestSchema } from "../../schema/rest.js"; +import type { + GetTokensByAddressParams, + GetTokensByAddressResult, +} from "../../types.js"; + +/** + * Fetches tokens (with optional metadata and prices) for one or more addresses + * across one or more networks in a single call. This is a multi-network + * request against the global Data API: networks travel in the request body, + * so the client's chain is not involved. + * + * @example + * ```ts + * import { mainnet, base } from "viem/chains"; + * + * const tokens = await getTokensByAddress(client, { + * addresses: [{ address: "0x...", networks: [mainnet, base, "solana-mainnet"] }], + * }); + * ``` + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetTokensByAddressParams} params Addresses paired with networks, plus options + * @returns {Promise} Token balances, metadata, and prices + */ +export async function getTokensByAddress( + client: DataClient, + params: GetTokensByAddressParams, +): Promise { + const { addresses, ...options } = params; + const restClient = getRestClient(client, DATA_API_URL); + return restClient.request({ + route: "assets/tokens/by-address", + method: "POST", + body: { + ...options, + addresses: addresses.map(({ address, networks }) => ({ + address, + networks: networks.map((n) => resolveNetwork(n).slug), + })), + }, + }); +} diff --git a/packages/data-apis/src/actions/transfers/getAssetTransfers.ts b/packages/data-apis/src/actions/transfers/getAssetTransfers.ts new file mode 100644 index 0000000000..f1726e9987 --- /dev/null +++ b/packages/data-apis/src/actions/transfers/getAssetTransfers.ts @@ -0,0 +1,50 @@ +import { alchemyTransport } from "@alchemy/common"; +import { getRpcUrl } from "../../internal/endpoints.js"; +import { + getTransportConfig, + resolveRequestNetwork, + type DataClient, +} from "../../internal/clientHelpers.js"; +import type { DataRpcSchema } from "../../schema/rpc.js"; +import type { + GetAssetTransfersParams, + GetAssetTransfersResult, +} from "../../types.js"; +import type { EIP1193RequestFn } from "viem"; + +/** + * Fetches historical asset transfers (external, internal, token) for the + * resolved network via the `alchemy_getAssetTransfers` JSON-RPC method. + * + * Without a `network` override this is a plain viem action over the client's + * Alchemy transport. With an override, a transport instance is derived from + * the client's transport config and pointed at the override network's RPC URL + * — the same mechanism the transport's tracing support uses. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetAssetTransfersParams} params Transfer filters and optional network override + * @returns {Promise} The matching transfers and pagination cursor + */ +export async function getAssetTransfers( + client: DataClient, + params: GetAssetTransfersParams, +): Promise { + const { network, ...rpcParams } = params; + + const request = (() => { + if (!network) { + return client.request as EIP1193RequestFn; + } + const { slug } = resolveRequestNetwork(client, network); + const derived = alchemyTransport({ + ...getTransportConfig(client), + url: getRpcUrl(slug), + })({ retryCount: 0 }); + return derived.request as EIP1193RequestFn; + })(); + + return request({ + method: "alchemy_getAssetTransfers", + params: [rpcParams], + }); +} diff --git a/packages/data-apis/src/client.ts b/packages/data-apis/src/client.ts new file mode 100644 index 0000000000..0af048d2f5 --- /dev/null +++ b/packages/data-apis/src/client.ts @@ -0,0 +1,79 @@ +import { + alchemyTransport, + resolveNetwork, + type AlchemyTransportConfig, + type NetworkInput, +} from "@alchemy/common"; +import { createClient, type Chain, type Client } from "viem"; +import { getRpcUrl } from "./internal/endpoints.js"; +import { dataActions, type DataActions } from "./decorator.js"; +import type { AlchemyTransport } from "@alchemy/common"; + +export type AlchemyDataClientOptions = Pick< + AlchemyTransportConfig, + "apiKey" | "jwt" | "url" | "fetchOptions" +> & { + /** + * Default network for network-scoped calls (NFT, Token, Transfers). + * Accepts a viem Chain, an Alchemy slug ("eth-mainnet"), or CAIP-2 + * ("eip155:1"). Multi-network calls (Portfolio) take explicit networks + * per request. + */ + network?: NetworkInput; +}; + +export type AlchemyDataClient = Client & + DataActions; + +/** + * Creates a Data API client. This is a convenience wrapper over + * `createClient` + `alchemyTransport` + the {@link dataActions} decorator — + * developers already holding a viem client with an Alchemy transport can use + * `client.extend(dataActions)` instead and get the identical behavior. + * + * @example + * ```ts + * import { createDataClient } from "@alchemy/data-apis"; + * + * const data = createDataClient({ + * apiKey: process.env.ALCHEMY_API_KEY, + * network: "eth-mainnet", // or `mainnet` from viem/chains, or "eip155:1" + * }); + * + * const nfts = await data.nft.getNftsForOwner({ owner: "0x..." }); + * ``` + * + * @param {AlchemyDataClientOptions} options Auth (apiKey/jwt/proxy url) and default network + * @returns {AlchemyDataClient} A viem client extended with the Data API actions + */ +export function createDataClient( + options: AlchemyDataClientOptions, +): AlchemyDataClient { + const { network, ...transportConfig } = options; + + // A viem Chain default flows through the transport's registry resolution + // untouched. Slug/CAIP-2 defaults are carried on a minimal chain definition + // (custom.alchemyNetwork) and the RPC URL is resolved up front — chain ID 0 + // mirrors how wallet-apis models Solana chains. + const chain: Chain | undefined = (() => { + if (network == null) return undefined; + if (typeof network === "object") return network; + const resolved = resolveNetwork(network); + return { + id: resolved.chainId ?? 0, + name: resolved.slug, + nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, + rpcUrls: { default: { http: [] } }, + custom: { alchemyNetwork: resolved.slug }, + }; + })(); + + const transport = alchemyTransport({ + ...transportConfig, + ...(chain && chain.custom?.alchemyNetwork && !transportConfig.url + ? { url: getRpcUrl(chain.custom.alchemyNetwork as string) } + : {}), + }); + + return createClient({ chain, transport }).extend(dataActions); +} diff --git a/packages/data-apis/src/dataClient.test.ts b/packages/data-apis/src/dataClient.test.ts new file mode 100644 index 0000000000..786656fbe2 --- /dev/null +++ b/packages/data-apis/src/dataClient.test.ts @@ -0,0 +1,126 @@ +import { alchemyTransport } from "@alchemy/common"; +import { createClient } from "viem"; +import { mainnet, base } from "viem/chains"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { createDataClient } from "./client.js"; +import { dataActions } from "./decorator.js"; + +const fetchMock = vi.fn(); + +const jsonResponse = (body: unknown) => + new Response(JSON.stringify(body), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); + +beforeEach(() => { + vi.stubGlobal("fetch", fetchMock); + fetchMock.mockReset(); +}); + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +describe("createDataClient", () => { + it("routes multi-network portfolio calls to the global Data API with resolved slugs", async () => { + fetchMock.mockResolvedValueOnce(jsonResponse({ data: { tokens: [] } })); + + const data = createDataClient({ + apiKey: "test-key", + network: "eth-mainnet", + }); + + await data.portfolio.getTokensByAddress({ + addresses: [ + // all three network input formats in one request + { address: "0xabc", networks: [mainnet, "base-mainnet", "eip155:10"] }, + { address: "0xdef", networks: ["solana-mainnet"] }, + ], + }); + + const [url, init] = fetchMock.mock.calls[0]!; + expect(url).toBe( + "https://api.g.alchemy.com/data/v1/assets/tokens/by-address", + ); + expect(init.method).toBe("POST"); + expect(JSON.parse(init.body)).toEqual({ + addresses: [ + { + address: "0xabc", + networks: ["eth-mainnet", "base-mainnet", "opt-mainnet"], + }, + { address: "0xdef", networks: ["solana-mainnet"] }, + ], + }); + }); + + it("routes NFT calls to the network-scoped URL, honoring per-request override", async () => { + fetchMock.mockImplementation(async () => + jsonResponse({ ownedNfts: [], totalCount: 0 }), + ); + + const data = createDataClient({ + apiKey: "test-key", + network: "eth-mainnet", + }); + + await data.nft.getNftsForOwner({ owner: "0xabc" }); + expect(String(fetchMock.mock.calls[0]![0])).toBe( + "https://eth-mainnet.g.alchemy.com/nft/v3/getNFTsForOwner?owner=0xabc", + ); + + await data.nft.getNftsForOwner({ owner: "0xabc", network: base }); + expect(String(fetchMock.mock.calls[1]![0])).toBe( + "https://base-mainnet.g.alchemy.com/nft/v3/getNFTsForOwner?owner=0xabc", + ); + }); + + it("routes transfers over JSON-RPC, deriving a transport for network overrides", async () => { + fetchMock.mockImplementation(async () => + jsonResponse({ jsonrpc: "2.0", id: 1, result: { transfers: [] } }), + ); + + const data = createDataClient({ + apiKey: "test-key", + network: "eth-mainnet", + }); + + const result = await data.transfers.getAssetTransfers({ + category: ["erc20"], + }); + expect(result).toEqual({ transfers: [] }); + expect(String(fetchMock.mock.calls[0]![0])).toContain( + "https://eth-mainnet.g.alchemy.com/v2", + ); + const rpcBody = JSON.parse(fetchMock.mock.calls[0]![1].body); + expect(rpcBody.method).toBe("alchemy_getAssetTransfers"); + expect(rpcBody.params).toEqual([{ category: ["erc20"] }]); + + await data.transfers.getAssetTransfers({ + category: ["erc20"], + network: "arb-mainnet", + }); + expect(String(fetchMock.mock.calls[1]![0])).toContain( + "https://arb-mainnet.g.alchemy.com/v2", + ); + }); +}); + +describe("dataActions decorator", () => { + it("behaves identically on a vanilla viem client with an Alchemy transport", async () => { + fetchMock.mockImplementation(async () => + jsonResponse({ ownedNfts: [], totalCount: 0 }), + ); + + const client = createClient({ + chain: mainnet, + transport: alchemyTransport({ apiKey: "test-key" }), + }).extend(dataActions); + + await client.nft.getNftsForOwner({ owner: "0xabc" }); + expect(String(fetchMock.mock.calls[0]![0])).toBe( + "https://eth-mainnet.g.alchemy.com/nft/v3/getNFTsForOwner?owner=0xabc", + ); + }); +}); diff --git a/packages/data-apis/src/decorator.ts b/packages/data-apis/src/decorator.ts new file mode 100644 index 0000000000..27e98ad87d --- /dev/null +++ b/packages/data-apis/src/decorator.ts @@ -0,0 +1,67 @@ +import type { + GetAssetTransfersParams, + GetAssetTransfersResult, + GetNftsForOwnerParams, + GetNftsForOwnerResult, + GetTokensByAddressParams, + GetTokensByAddressResult, +} from "./types.js"; +import type { DataClient } from "./internal/clientHelpers.js"; +import { getTokensByAddress } from "./actions/portfolio/getTokensByAddress.js"; +import { getNftsForOwner } from "./actions/nft/getNftsForOwner.js"; +import { getAssetTransfers } from "./actions/transfers/getAssetTransfers.js"; + +/** The namespaced Data API actions attached by the {@link dataActions} decorator. */ +export type DataActions = { + portfolio: { + getTokensByAddress: ( + params: GetTokensByAddressParams, + ) => Promise; + }; + nft: { + getNftsForOwner: ( + params: GetNftsForOwnerParams, + ) => Promise; + }; + transfers: { + getAssetTransfers: ( + params: GetAssetTransfersParams, + ) => Promise; + }; +}; + +/** + * A viem client decorator that attaches the Data API actions, grouped by + * namespace, to any client configured with an Alchemy transport. + * + * @example + * ```ts + * import { createClient } from "viem"; + * import { mainnet } from "viem/chains"; + * import { alchemyTransport } from "@alchemy/common"; + * import { dataActions } from "@alchemy/data-apis"; + * + * const client = createClient({ + * chain: mainnet, + * transport: alchemyTransport({ apiKey: "..." }), + * }).extend(dataActions); + * + * const nfts = await client.nft.getNftsForOwner({ owner: "0x..." }); + * ``` + * + * @param {DataClient} client The client to decorate + * @returns {DataActions} The namespaced Data API actions + */ +export function dataActions(client: DataClient): DataActions { + return { + portfolio: { + getTokensByAddress: (params) => getTokensByAddress(client, params), + }, + nft: { + getNftsForOwner: (params) => getNftsForOwner(client, params), + }, + transfers: { + getAssetTransfers: (params) => getAssetTransfers(client, params), + }, + }; +} diff --git a/packages/data-apis/src/generated/rest/nft.schema.ts b/packages/data-apis/src/generated/rest/nft.schema.ts new file mode 100644 index 0000000000..c543c83c66 --- /dev/null +++ b/packages/data-apis/src/generated/rest/nft.schema.ts @@ -0,0 +1,36 @@ +/* eslint-disable -- machine-generated file */ +// AUTO-GENERATED by @alchemy/api-codegen — DO NOT EDIT. +// Regenerate with `pnpm generate`. Spec provenance (docs repo commit + checksums) +// is recorded in packages/api-codegen/specs/specs.lock.json. + +import type { RestRequestSchema } from "@alchemy/common"; +import type { operations } from "./nft.types.js"; + +/** 200 response for getNFTsForOwner-v3. */ +export type GetNftsForOwnerResponse = + operations["getNFTsForOwner-v3"]["responses"]["200"]["content"]["application/json"]; + +/** + * Query params for getNFTsForOwner-v3. Sent via the URL at runtime; + * RestRequestSchema has no query channel, so this is exposed as a + * standalone type for the SDK's params layer. + */ +export type GetNftsForOwnerQuery = NonNullable< + operations["getNFTsForOwner-v3"]["parameters"]["query"] +>; + +/** RestRequestSchema entries for the nft REST API. */ +export type NftRestSchema = readonly [ + { + /** GET /v3/{apiKey}/getNFTsForOwner (operationId: getNFTsForOwner-v3) */ + Route: "getNFTsForOwner"; + Method: "GET"; + Body?: undefined; + Response: GetNftsForOwnerResponse; + }, +]; + +/** Compile-time guard that the emitted tuple satisfies the shared constraint. */ +export type _AssertNftRestSchema = NftRestSchema extends RestRequestSchema + ? true + : never; diff --git a/packages/data-apis/src/generated/rest/nft.types.ts b/packages/data-apis/src/generated/rest/nft.types.ts new file mode 100644 index 0000000000..523cc926b4 --- /dev/null +++ b/packages/data-apis/src/generated/rest/nft.types.ts @@ -0,0 +1,5214 @@ +/* eslint-disable -- machine-generated file */ +// AUTO-GENERATED by @alchemy/api-codegen — DO NOT EDIT. +// Regenerate with `pnpm generate`. Spec provenance (docs repo commit + checksums) +// is recorded in packages/api-codegen/specs/specs.lock.json. + +export interface paths { + "/v3/{apiKey}/getNFTsForOwner": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * NFTs By Owner + * @description getNFTsForOwner - Retrieves all NFTs currently owned by a specified address. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains). + */ + get: operations["getNFTsForOwner-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/getNFTsForContract": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * NFTs By Contract + * @description getNFTsForContract - Retrieves all NFTs associated with a specific NFT contract. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains). + */ + get: operations["getNFTsForContract-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/getNFTsForCollection": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * NFTs By Collection + * @description getNFTsForCollection - Retrieves all NFTs associated with a specific NFT collection. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains). + */ + get: operations["getNFTsForCollection-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/getNFTMetadata": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * NFT Metadata By Token ID + * @description getNFTMetadata - Retrieves the metadata associated with a specific NFT. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains). + */ + get: operations["getNFTMetadata-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/getNFTMetadataBatch": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * NFT Metadata By Token ID [Batch] + * @description getNFTMetadataBatch - Retrieves metadata for up to 100 specified NFT contracts in a single request. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains). + */ + post: operations["getNFTMetadataBatch-v3"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/getContractMetadata": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Contract Metadata By Address + * @description getContractMetadata - Retrieves high-level collection or contract-level information for an NFT. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains). + */ + get: operations["getContractMetadata-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/getCollectionMetadata": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Collection Metadata By Slug + * @description getCollectionMetadata - Retrieves high-level collection or contract-level information for an NFT collection. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains). + */ + get: operations["getCollectionMetadata-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/invalidateContract": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Invalidate Contract Cache + * @description Marks all cached tokens for the specified contract as stale, ensuring the next query fetches live data instead of cached data. + * + * Please note that this endpoint is only available on **Ethereum**, **Polygon**, **Arbitrum**, **Optimism** & **Base** networks. + */ + get: operations["invalidateContract-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/getContractMetadataBatch": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Contract Metadata By Address [Batch] + * @description getContractMetadataBatch - Retrieves metadata for a list of specified contract addresses in a single request. + */ + post: operations["getContractMetadataBatch-v3"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/getOwnersForNFT": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Owners By NFT + * @description getOwnersForNFT - Retrieves the owner(s) for a specific token. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains). + */ + get: operations["getOwnersForNFT-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/getOwnersForContract": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Owners By Contract + * @description getOwnersForContract - Retrieves all owners associated with a specific NFT contract. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains). + */ + get: operations["getOwnersForContract-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/getSpamContracts": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Spam Contracts + * @description Returns a list of all spam contracts marked by Alchemy. + * + * Please note that this API endpoint is only available to paid tier customers. Upgrade your account [here](https://dashboard.alchemy.com/account). + * + * Spam NFT functionality is available on Mainnet for the following chains: Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast. More to come soon! + */ + get: operations["getSpamContracts-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/isSpamContract": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Is Spam Contract + * @description Determines whether a specific contract is marked as spam by Alchemy. + * + * Please note that this API endpoint is only available to paid tier customers. Upgrade your account [here](https://dashboard.alchemy.com/account). + * + * Spam NFT functionality is available on Mainnet for the following chains: Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast. More to come soon! + */ + get: operations["isSpamContract-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/isAirdropNFT": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Is Airdrop NFT + * @description Determines whether a specific token is marked as an airdrop. Airdrops are defined as NFTs minted to a user address in a transaction sent by a different address. + * + * Please note that this endpoint is only available on Ethereum (mainnet only) & Polygon (mainnet, amoy & mumbai). + */ + get: operations["isAirdropNFT-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/summarizeNFTAttributes": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Attributes Summary By Contract + * @description Generates a summary of attribute prevalence for a specific NFT collection. + * + * Please note that this endpoint is only available on Ethereum (mainnet) & Polygon (mainnet & mumbai). + */ + get: operations["summarizeNFTAttributes-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/getFloorPrice": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Floor Prices By Slug + * @description Retrieves the floor prices of an NFT collection across different marketplaces. + * + * Please note that this endpoint is only available on Ethereum mainnet for Opensea & Looksrare marketplaces. + */ + get: operations["getFloorPrice-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/searchContractMetadata": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Search Contract Metadata + * @description Searches for a keyword across metadata of all ERC-721 and ERC-1155 smart contracts. + * + * This endpoint is currently in BETA. If you have any questions or feedback, please contact us at support@alchemy.com or open a ticket in the dashboard. + * + * Please note that this endpoint is only available on **Ethereum**, **Polygon**, **Arbitrum**, **Optimism** & **Base** networks. + */ + get: operations["searchContractMetadata-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/isHolderOfContract": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Is Holder Of Contract + * @description isHolderOfContract - Determines whether a specific wallet holds any NFT from a given contract. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains). + */ + get: operations["isHolderOfContract-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/computeRarity": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Attribute Rarity By NFT + * @description Calculates the rarity of each attribute within an NFT. + * + * Please note that this endpoint is only available on Ethereum (mainnet) & Polygon (mainnet & mumbai). + */ + get: operations["computeRarity-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/getNFTSales": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * NFT Sales + * @description Retrieves NFT sales that have occurred through on-chain marketplaces. + * + * Please note that this endpoint is only available on Ethereum (Seaport, Wyvern, X2Y2, Blur, LooksRare, Cryptopunks), Polygon (Seaport) & Optimism (Seaport) mainnets. + */ + get: operations["getNFTSales-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/getContractsForOwner": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Contracts By Owner + * @description getContractsForOwner - Retrieves all NFT contracts held by a specified owner address. + */ + get: operations["getContractsForOwner-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/getCollectionsForOwner": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Collections By Owner + * @description Retrieves all NFT collections held by a specified owner address. + * + * This endpoint is only supported on Ethereum. Use `getContractsForOwner` for support across all other chains we support! + */ + get: operations["getCollectionsForOwner-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/reportSpam": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Report Spam Address + * @description Reports a specific address to the API if it is suspected to be spam. + * + * Spam NFT functionality is available on Mainnet for the following chains: Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast. More to come soon! + */ + get: operations["reportSpam-v3"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v3/{apiKey}/refreshNftMetadata": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Refresh NFT Metadata + * @description Submits a request for Alchemy to refresh the cached metadata of a specific NFT token. + * + * Please note that this endpoint is only supported on Ethereum (Mainnet & Sepolia), Polygon (Mainnet, Mumbai & Amoy), Arbitrum One (mainnet), Optimism (mainnet) & Base (mainnet). For other chains, you could use the `getNFTMetadata` endpoint with the `refreshCache` parameter set to `true` to refresh the metadata! + */ + post: operations["refreshNftMetadata-v3"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/getNFTs": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * getNFTs + * @description Gets all NFTs currently owned by a given address. + */ + get: operations["getNFTs"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/getNFTMetadata": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * getNFTMetadata + * @description Gets the metadata associated with a given NFT. + */ + get: operations["getNFTMetadata"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/getNFTMetadataBatch": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * getNFTMetadataBatch + * @description Gets the metadata associated with up to 100 given NFT contracts. + */ + post: operations["getNFTMetadataBatch"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/getContractMetadata": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * getContractMetadata + * @description Queries NFT high-level collection/contract level information. + */ + get: operations["getContractMetadata"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/getContractMetadataBatch": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * getContractMetadataBatch + * @description Gets the metadata associated with the given list of contract addresses + */ + post: operations["getContractMetadataBatch"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/getNFTsForCollection": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * getNFTsForCollection + * @description Gets all NFTs for a given NFT contract. + */ + get: operations["getNFTsForCollection"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/getOwnersForToken": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * getOwnersForToken + * @description Get the owner(s) for a token. + */ + get: operations["getOwnersForToken"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/getOwnersForCollection": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * getOwnersForCollection + * @description Gets all owners for a given NFT contract. + */ + get: operations["getOwnersForCollection"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/getSpamContracts": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * getSpamContracts + * @description Returns a list of all spam contracts marked by Alchemy. + */ + get: operations["getSpamContracts"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/isSpamContract": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * isSpamContract + * @description Returns whether a contract is marked as spam or not by Alchemy. + */ + get: operations["isSpamContract"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/isAirdrop": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * isAirdrop + * @description Returns whether a token is marked as an airdrop or not. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. + */ + get: operations["isAirdrop"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/invalidateContract": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * invalidateContract + * @description Marks all cached tokens for the particular contract as stale. So the next time the endpoint is queried it fetches live data instead of fetching from cache. + */ + get: operations["invalidateContract"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/getFloorPrice": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * getFloorPrice + * @description Returns the floor prices of a NFT collection by marketplace. + */ + get: operations["getFloorPrice"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/computeRarity": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * computeRarity + * @description Computes the rarity of each attribute of an NFT. + */ + get: operations["computeRarity"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/searchContractMetadata": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * searchContractMetadata + * @description Search for a keyword across metadata of all ERC-721 and ERC-1155 smart contracts + */ + get: operations["searchContractMetadata"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/summarizeNFTAttributes": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * summarizeNFTAttributes + * @description Generate a summary of attribute prevalence for an NFT collection. + */ + get: operations["summarizeNFTAttributes"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/isHolderOfCollection": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * isHolderOfCollection + * @description Checks whether a wallet holds a NFT in a given collection + */ + get: operations["isHolderOfCollection"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/getNFTSales": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * getNFTSales + * @description Gets NFT sales that have happened through on-chain marketplaces + */ + get: operations["getNFTSales"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/getContractsForOwner": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * getContractsForOwner + * @description Gets all NFT contracts held by an owner address. + */ + get: operations["getContractsForOwner"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/{apiKey}/reportSpam": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * reportSpam + * @description Report a particular address to our APIs if you think it is spam + */ + get: operations["reportSpam"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; +} +export type webhooks = Record; +export interface components { + schemas: { + /** @description Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract */ + rawv3: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually. */ + metadata?: { + /** @description String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces. */ + image?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms) */ + description?: string; + /** @description Object - Traits/attributes/characteristics for each NFT asset. */ + attributes?: { + value?: string; + trait_type?: string; + }[]; + }; + /** @description String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT. */ + error?: string; + }; + id: { + /** @default 44 */ + tokenId: string; + tokenMetadata?: { + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + }; + }; + idV3: { + /** @default 44 */ + tokenId: string; + tokenMetadata?: { + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + }; + }; + tokenUri: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + }; + /** @description Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually. */ + metadata: { + /** @description String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces. */ + image?: string; + /** @description String - The image URL that appears alongside the asset image on NFT platforms. */ + external_url?: string; + /** @description String - Background color of the NFT item. Usually must be defined as a six-character hexadecimal. */ + background_color?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms) */ + description?: string; + /** @description Object - Traits/attributes/characteristics for each NFT asset. */ + attributes?: { + value?: string; + trait_type?: string; + }[]; + media?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + /** @description URL for a resized thumbnail of the NFT media asset. */ + thumbnail?: string; + /** @description The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets. */ + format?: string; + /** @description The size of the media asset in bytes. */ + bytes?: number; + }[]; + }; + /** @description The object that represents a smart contract and has all data corresponding to that contract */ + ownedContract: { + /** @description Address of the held contract */ + address?: string; + /** @description Sum of NFT balances across all token IDs held by the owner. For non-fungible tokens this will be equal to the `numDistinctTokensOwned`, but it may be higher if the user holds some fungible ERC1155 tokens. */ + totalBalance?: number; + /** @description Number of distinct token IDs held by the owner. For non-fungible tokens this will be equal to the `totalBalance`, but it may be lower if the user holds some fungible ERC1155 tokens. */ + numDistinctTokensOwned?: number; + isSpam?: boolean; + /** @description One of the tokens from this contract held by the owner. */ + tokenId?: string; + /** @description The name of the contract, i.e. "Bored Ape Yacht Club". */ + name?: string; + /** @description The title of the token held by the owner i.e. "Something #22". */ + title?: string; + /** @description The symbol of the contract, i.e. BAYC. */ + symbol?: string; + /** @description The NFT standard used by the contract, i.e. ERC721 or ERC1155. */ + tokenType?: string; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + media?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + /** @description URL for a resized thumbnail of the NFT media asset. */ + thumbnail?: string; + /** @description The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets. */ + format?: string; + /** @description The size of the media asset in bytes. */ + bytes?: number; + }[]; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + opensea?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + }; + /** @description The object that represents a smart contract and has all data corresponding to that contract */ + ownedContractv3: { + /** @default 0xe785E82358879F061BC3dcAC6f0444462D4b5330 */ + address: string; + /** @description The name of the contract, i.e. "Bored Ape Yacht Club". */ + name?: string; + /** @description The symbol of the contract, i.e. BAYC. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + tokenType?: string; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + /** @description Sum of NFT balances across all token IDs held by the owner. For non-fungible tokens this will be equal to the `numDistinctTokensOwned`, but it may be higher if the user holds some fungible ERC1155 tokens. */ + totalBalance?: number; + /** @description Number of distinct token IDs held by the owner. For non-fungible tokens this will be equal to the `totalBalance`, but it may be lower if the user holds some fungible ERC1155 tokens. */ + numDistinctTokensOwned?: number; + /** @description `True` if the contract is detected as spam contract. `False` if it is not spam or has not been evaluated by our system yet */ + isSpam?: boolean; + /** @description Details of the display NFT for this contract. This NFT and its image can be used to represent the contract when displaying info about it. */ + displayNft?: { + /** @description One of the tokens from this contract held by the owner. */ + tokenId?: string; + /** @description The title of the token held by the owner i.e. "Something #22". */ + name?: string; + }; + /** @description Details of the image corresponding to this contract */ + image?: { + /** @description The Url of the image stored in Alchemy cache */ + cachedUrl?: string; + /** @description The Url that has the thumbnail version of the NFT */ + thumbnailUrl?: string; + /** @description The Url that has the NFT image in png */ + pngUrl?: string; + /** @description The Url of the image stored in Alchemy cache */ + contentType?: string; + /** @description The size of the media asset in bytes. */ + size?: number; + /** @description The original Url of the image coming straight from the smart contract */ + originalUrl?: string; + }; + }; + /** @description Metadata for an NFT collection held by an owner address. Includes general metadata about the collection, as well as information specific to the owner such as the total balance and the token ID of a random NFT for display purposes. */ + ownedCollectionv3: { + /** @description The name of the collection, i.e. "Bored Ape Yacht Club". */ + name?: string; + /** @description The human-readable string used to identify the collection on OpenSea. */ + slug?: string; + /** @description Floor price data for the collection */ + floorPrice?: { + /** @description The marketplace the floor price is on */ + marketplace?: string; + /** @description Floor price of the collection on the marketplace */ + floorPrice?: number; + /** @description The currency of the floor price */ + priceCurrency?: string; + }; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description Contract-level data for a collection, such as contract type, name, and symbol. */ + contract?: { + /** @description Address of the contract */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + }; + /** @description Sum of NFT balances across all token IDs held by the owner. For non-fungible tokens this will be equal to the `numDistinctTokensOwned`, but it may be higher if the user holds some fungible ERC1155 tokens. */ + totalBalance?: number; + /** @description Number of distinct token IDs held by the owner. For non-fungible tokens this will be equal to the `totalBalance`, but it may be lower if the user holds some fungible ERC1155 tokens. */ + numDistinctTokensOwned?: number; + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description Details of the display NFT for this contract. This NFT and its image can be used to represent the contract when displaying info about it. */ + displayNft?: { + /** @description One of the tokens from this contract held by the owner. */ + tokenId?: string; + /** @description The title of the token held by the owner i.e. "Something #22". */ + name?: string; + }; + /** @description Details of the image corresponding to this contract */ + image?: { + /** @description The Url of the image stored in Alchemy cache */ + cachedUrl?: string; + /** @description The Url that has the thumbnail version of the NFT */ + thumbnailUrl?: string; + /** @description The Url that has the NFT image in png */ + pngUrl?: string; + /** @description The Url of the image stored in Alchemy cache */ + contentType?: string; + /** @description The size of the media asset in bytes. */ + size?: number; + /** @description The original Url of the image coming straight from the smart contract */ + originalUrl?: string; + }; + }; + /** @description Contract-level data for a collection, such as contract type, name, and symbol. */ + ownedCollectionContract: { + /** @description Address of the contract */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + }; + media: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + /** @description URL for a resized thumbnail of the NFT media asset. */ + thumbnail?: string; + /** @description The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets. */ + format?: string; + /** @description The size of the media asset in bytes. */ + bytes?: number; + }[]; + /** @description The object that represents an NFT and has all data corresponding to that NFT */ + ownedNFT: { + /** @description Object - Contract for returned NFT */ + contract?: { + /** @description String - Address of NFT contract. */ + address?: string; + }; + id?: { + /** @default 44 */ + tokenId: string; + tokenMetadata?: { + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + }; + }; + /** @description String - Token balance */ + balance?: string; + /** @description String - Name of the NFT asset. */ + title?: string; + /** @description String - Brief human-readable description */ + description?: string; + tokenUri?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + }; + media?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + /** @description URL for a resized thumbnail of the NFT media asset. */ + thumbnail?: string; + /** @description The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets. */ + format?: string; + /** @description The size of the media asset in bytes. */ + bytes?: number; + }; + /** @description Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually. */ + metadata?: { + /** @description String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces. */ + image?: string; + /** @description String - The image URL that appears alongside the asset image on NFT platforms. */ + external_url?: string; + /** @description String - Background color of the NFT item. Usually must be defined as a six-character hexadecimal. */ + background_color?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms) */ + description?: string; + /** @description Object - Traits/attributes/characteristics for each NFT asset. */ + attributes?: { + value?: string; + trait_type?: string; + }[]; + media?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + /** @description URL for a resized thumbnail of the NFT media asset. */ + thumbnail?: string; + /** @description The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets. */ + format?: string; + /** @description The size of the media asset in bytes. */ + bytes?: number; + }[]; + }; + /** @description String - ISO timestamp of the last cache refresh for the information returned in the metadata field. */ + timeLastUpdated?: string; + /** @description String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT. */ + error?: string; + contractMetadata?: { + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + opensea?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + }; + /** @description Information about whether and why a contract was marked as spam. */ + spamInfo?: { + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description List of reasons why a contract was classified as spam. **Only available on paid tiers.** */ + spamClassifications?: string[]; + }; + /** @description Only present if the request specified `orderBy=transferTime`. */ + acquiredAt?: { + /** @description Block timestamp of the block where the NFT was most recently acquired. */ + blockTimestamp?: string; + /** @description Block number of the block where the NFT was most recently acquired. */ + blockNumber?: string; + }; + }; + /** @description The object that represents an NFT and has all data corresponding to that NFT */ + ownedNFTv3: { + /** @description The contract object that has details of a contract */ + contract?: { + /** @description Address of the held contract */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description List of reasons why a contract was classified as spam. **Only available on paid tiers.** */ + spamClassifications?: string[]; + }; + /** @default 44 */ + tokenId: string; + tokenType?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Brief human-readable description */ + description?: string; + /** @description Details of the image corresponding to this contract */ + image?: { + /** @description The Url of the image stored in Alchemy cache */ + cachedUrl?: string; + /** @description The Url that has the thumbnail version of the NFT */ + thumbnailUrl?: string; + /** @description The Url that has the NFT image in png */ + pngUrl?: string; + /** @description The Url of the image stored in Alchemy cache */ + contentType?: string; + /** @description The size of the media asset in bytes. */ + size?: number; + /** @description The original Url of the image coming straight from the smart contract */ + originalUrl?: string; + }; + /** @description Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract */ + raw?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually. */ + metadata?: { + /** @description String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces. */ + image?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms) */ + description?: string; + /** @description Object - Traits/attributes/characteristics for each NFT asset. */ + attributes?: { + value?: string; + trait_type?: string; + }[]; + }; + /** @description String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT. */ + error?: string; + }; + /** @description The collection object that has details of a collection */ + collection?: { + /** @description String - Collection name */ + name?: string; + /** @description String - OpenSea collection slug */ + slug?: string; + /** @description String - URL for the external site of the collection */ + externalUrl?: string; + /** @description String - Banner image URL for the collection */ + bannerImageUrl?: string; + }; + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description String - ISO timestamp of the last cache refresh for the information returned in the metadata field. */ + timeLastUpdated?: string; + /** @description Only present if the request specified `orderBy=transferTime`. */ + acquiredAt?: { + /** @description Block timestamp of the block where the NFT was most recently acquired. */ + blockTimestamp?: string; + /** @description Block number of the block where the NFT was most recently acquired. */ + blockNumber?: string; + }; + animation?: { + cachedUrl?: string; + contentType?: string; + size?: number; + orginalUrl?: string; + }; + mint?: { + /** @description Address that minted the NFT */ + mintAddress?: string; + /** @description Block number when the NFT was minted */ + blockNumber?: number; + /** @description Timestamp when the NFT was minted */ + timestamp?: string; + /** @description Transaction hash of the mint transaction */ + transactionHash?: string; + }; + /** @description List of all addresses that own the given NFT. */ + owners?: string[]; + }; + contractMetadata: { + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + opensea?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + }; + contractMetadatav3: { + /** @description String - Contract address for the queried NFT collection */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + }; + collectionMetadatav3: { + /** @description String - Name of the queried NFT Collection */ + name?: string; + /** @description The human-readable string used to identify the collection on OpenSea. */ + slug?: string; + /** @description Floor price data for the collection */ + floorPrice?: { + /** @description The marketplace the floor price is on */ + marketplace?: string; + /** @description Floor price of the collection on the marketplace */ + floorPrice?: number; + /** @description The currency of the floor price */ + priceCurrency?: string; + }; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + }; + /** @description The contract object that has details of a contract */ + contractv3: { + /** @description Address of the held contract */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description List of reasons why a contract was classified as spam. **Only available on paid tiers.** */ + spamClassifications?: string[]; + }; + }; + responses: never; + parameters: { + apiKey: string; + /** @description String - Address for NFT owner (can be in ENS format for Eth Mainnet). */ + owner: string; + /** @description String - Wallet address to check for contract ownership. */ + wallet: string; + /** @description String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results. */ + pageKey: string; + /** @description Number of NFTs to be returned per page. Defaults to 100. Max is 100. */ + pageSize: number; + /** @description Number of owners to be returned per page. */ + getOwnersForTokenPageSize: number; + /** @description Array of contract addresses to filter the responses with. Max limit 45 contracts. */ + contractAddresses: string[]; + /** @description Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. */ + withMetadata: boolean; + /** + * @description Array of filters (as ENUMS) that will be applied to the query. NFTs that match one or more of these filters will be excluded from the response. May not be used in conjunction with includeFilters[]. Filter Options: + * - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**. + * - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only. + * - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts) + */ + excludeFilters: ("SPAM" | "AIRDROPS")[]; + /** @description String - any valid blockchain address for NFT collections, contracts, mints, etc. */ + address: string; + /** @description String - any valid blockchain address for NFT collections, contracts, mints, etc. */ + addressRequired: string; + /** + * @description Array of filters (as ENUMS) that will be applied to the query. Only NFTs that match one or more of these filters will be included in the response. May not be used in conjunction with excludeFilters[]. Filter Options: + * - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**. + * - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only. + * - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts) + */ + includeFilters: ("SPAM" | "AIRDROPS")[]; + /** + * @description Enum - the confidence level at which to filter spam at. + * + * Confidence Levels: + * - VERY_HIGH + * - HIGH + * - MEDIUM + * - LOW + * + * The confidence level set means that any spam that is at that confidence level or higher will be filtered out. For example, if the confidence level is HIGH, contracts that we have HIGH or VERY_HIGH confidence in being spam will be filtered out from the response. + * Defaults to VERY_HIGH for Ethereum Mainnet and MEDIUM for Matic Mainnet. + * + * **Please note that this filter is only available on paid tiers. Upgrade your account [here](https://dashboard.alchemy.com/settings/billing/).** + */ + spamConfidenceLevel: "VERY_HIGH" | "HIGH" | "MEDIUM" | "LOW"; + /** @description String - OpenSea slug for the NFT collection. */ + collectionSlug: string; + /** @description String - OpenSea slug for the NFT collection. */ + collectionSlugRequired: string; + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddressRequired: string; + /** @description String - The ID of the token. Can be in hex or decimal format. */ + tokenId: string; + /** @description String - The ID of the token in decimal format. */ + tokenIdV3: string; + /** @description String - The ID of the token. Can be in hex or decimal format. */ + tokenIdForNFTSales: string; + /** @description String - 'ERC721' or 'ERC1155'; specifies type of token to query for. API requests will perform faster if this is specified. */ + tokenType: string; + /** @description String - A tokenID offset used for pagination. Can be a hex string, or a decimal. Users can specify the offset themselves to start from a custom offset, or to fetch multiple token ranges in parallel. */ + startToken: string; + /** @description Integer - Sets the total number of NFTs returned in the response. Defaults to 100. */ + limit: number; + /** @description No set timeout by default - When metadata is requested, this parameter is the timeout (in milliseconds) for the website hosting the metadata to respond. If you want to _only_ access the cache and not live fetch any metadata for cache misses then set this value to 0. */ + tokenUriTimeoutInMs: number; + /** @description Boolean - If set to `true` the query will include the token balances per token id for each owner. `false` by default. */ + withTokenBalances: boolean; + /** @description Defaults to false for faster response times. If true will refresh metadata for given token. If false will check the cache and use it or refresh if cache doesn't exist. */ + refreshCache: boolean; + /** @description String - The point in time or block number (in hex or decimal) to fetch collection ownership information for. */ + block: string; + /** @description String - The block number to start fetching NFT sales data from. Allowed values are decimal and hex integers, and "latest". Defaults to "0". */ + fromBlock: string; + /** @description Enum - Whether to return the results ascending from startBlock or descending from startBlock. Defaults to descending (false). */ + order: "asc" | "desc"; + /** + * @description Enum - ordering scheme to use for ordering NFTs in the response. If unspecified, NFTs will be ordered by contract address and token ID. + * - transferTime: NFTs will be ordered by the time they were transferred into the wallet, with newest NFTs first. Note: This ordering is supported on Ethereum Mainnet, Optimism Mainnet, Polygon Mainnet, Base Mainnet, Arbitrum One, Polygon Amoy, Base Sepolia, Arbitrum Sepolia, Ethereum Sepolia, and Optimism Sepolia. + */ + orderBy: "transferTime"; + /** @description Enum - The name of the NFT marketplace to filter sales by. The endpoint currently supports "seaport", "wyvern", "looksrare", "x2y2", "blur", and "cryptopunks". Defaults to returning sales from all supported marketplaces. */ + marketplace: + | "seaport" + | "looksrare" + | "x2y2" + | "wyvern" + | "blur" + | "cryptopunks"; + /** @description String - The address of the NFT buyer to filter sales by. Defaults to returning sales involving any buyer. */ + buyerAddress: string; + /** @description String - The address of the NFT seller to filter sales by. Defaults to returning sales involving any seller. */ + sellerAddress: string; + /** @description Enum - Filter by whether the buyer or seller was the taker in the NFT trade. Allowed filter values are "BUYER" and "SELLER". Defaults to returning both buyer and seller taker trades. */ + taker: "BUYER" | "SELLER"; + /** @description String - The search string that you want to search for in contract metadata */ + query: string; + }; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export interface operations { + "getNFTsForOwner-v3": { + parameters: { + query: { + /** @description String - Address for NFT owner (can be in ENS format for Eth Mainnet). */ + owner: string; + /** @description Array of contract addresses to filter the responses with. Max limit 45 contracts. */ + "contractAddresses[]"?: string[]; + /** @description Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. */ + withMetadata?: boolean; + /** + * @description Enum - ordering scheme to use for ordering NFTs in the response. If unspecified, NFTs will be ordered by contract address and token ID. + * - transferTime: NFTs will be ordered by the time they were transferred into the wallet, with newest NFTs first. Note: This ordering is supported on Ethereum Mainnet, Optimism Mainnet, Polygon Mainnet, Base Mainnet, Arbitrum One, Polygon Amoy, Base Sepolia, Arbitrum Sepolia, Ethereum Sepolia, and Optimism Sepolia. + */ + orderBy?: "transferTime"; + /** + * @description Array of filters (as ENUMS) that will be applied to the query. NFTs that match one or more of these filters will be excluded from the response. May not be used in conjunction with includeFilters[]. Filter Options: + * - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**. + * - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only. + * - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts) + */ + "excludeFilters[]"?: ("SPAM" | "AIRDROPS")[]; + /** + * @description Array of filters (as ENUMS) that will be applied to the query. Only NFTs that match one or more of these filters will be included in the response. May not be used in conjunction with excludeFilters[]. Filter Options: + * - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**. + * - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only. + * - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts) + */ + "includeFilters[]"?: ("SPAM" | "AIRDROPS")[]; + /** + * @description Enum - the confidence level at which to filter spam at. + * + * Confidence Levels: + * - VERY_HIGH + * - HIGH + * - MEDIUM + * - LOW + * + * The confidence level set means that any spam that is at that confidence level or higher will be filtered out. For example, if the confidence level is HIGH, contracts that we have HIGH or VERY_HIGH confidence in being spam will be filtered out from the response. + * Defaults to VERY_HIGH for Ethereum Mainnet and MEDIUM for Matic Mainnet. + * + * **Please note that this filter is only available on paid tiers. Upgrade your account [here](https://dashboard.alchemy.com/settings/billing/).** + */ + spamConfidenceLevel?: "VERY_HIGH" | "HIGH" | "MEDIUM" | "LOW"; + /** @description No set timeout by default - When metadata is requested, this parameter is the timeout (in milliseconds) for the website hosting the metadata to respond. If you want to _only_ access the cache and not live fetch any metadata for cache misses then set this value to 0. */ + tokenUriTimeoutInMs?: number; + /** @description String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results. */ + pageKey?: string; + /** @description Number of NFTs to be returned per page. Defaults to 100. Max is 100. */ + pageSize?: number; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns the list of all NFTs owned by the given address and satisfying the given input parameters. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Array of the NFT objects corresponding to the NFTs owned by the owner */ + ownedNfts?: { + /** @description The contract object that has details of a contract */ + contract?: { + /** @description Address of the held contract */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description List of reasons why a contract was classified as spam. **Only available on paid tiers.** */ + spamClassifications?: string[]; + }; + /** @default 44 */ + tokenId: string; + tokenType?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Brief human-readable description */ + description?: string; + /** @description Details of the image corresponding to this contract */ + image?: { + /** @description The Url of the image stored in Alchemy cache */ + cachedUrl?: string; + /** @description The Url that has the thumbnail version of the NFT */ + thumbnailUrl?: string; + /** @description The Url that has the NFT image in png */ + pngUrl?: string; + /** @description The Url of the image stored in Alchemy cache */ + contentType?: string; + /** @description The size of the media asset in bytes. */ + size?: number; + /** @description The original Url of the image coming straight from the smart contract */ + originalUrl?: string; + }; + /** @description Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract */ + raw?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually. */ + metadata?: { + /** @description String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces. */ + image?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms) */ + description?: string; + /** @description Object - Traits/attributes/characteristics for each NFT asset. */ + attributes?: { + value?: string; + trait_type?: string; + }[]; + }; + /** @description String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT. */ + error?: string; + }; + /** @description The collection object that has details of a collection */ + collection?: { + /** @description String - Collection name */ + name?: string; + /** @description String - OpenSea collection slug */ + slug?: string; + /** @description String - URL for the external site of the collection */ + externalUrl?: string; + /** @description String - Banner image URL for the collection */ + bannerImageUrl?: string; + }; + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description String - ISO timestamp of the last cache refresh for the information returned in the metadata field. */ + timeLastUpdated?: string; + /** @description Only present if the request specified `orderBy=transferTime`. */ + acquiredAt?: { + /** @description Block timestamp of the block where the NFT was most recently acquired. */ + blockTimestamp?: string; + /** @description Block number of the block where the NFT was most recently acquired. */ + blockNumber?: string; + }; + animation?: { + cachedUrl?: string; + contentType?: string; + size?: number; + orginalUrl?: string; + }; + mint?: { + /** @description Address that minted the NFT */ + mintAddress?: string; + /** @description Block number when the NFT was minted */ + blockNumber?: number; + /** @description Timestamp when the NFT was minted */ + timestamp?: string; + /** @description Transaction hash of the mint transaction */ + transactionHash?: string; + }; + /** @description List of all addresses that own the given NFT. */ + owners?: string[]; + }[]; + /** @description Integer - Total number of NFTs (distinct `tokenIds`) owned by the given address. */ + totalCount?: number; + pageKey?: string; + /** @description Block Information of the block as of which the corresponding data is valid */ + validAt?: { + /** @description The block number above information is valid as of */ + blockNumber?: number; + /** @description The block hash above information is valid as of */ + blockHash?: string; + /** @description The block timestamp above information is valid as of */ + blockTimestamp?: string; + }; + }; + }; + }; + }; + }; + "getNFTsForContract-v3": { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + /** @description Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. */ + withMetadata?: boolean; + /** @description String - A tokenID offset used for pagination. Can be a hex string, or a decimal. Users can specify the offset themselves to start from a custom offset, or to fetch multiple token ranges in parallel. */ + startToken?: string; + /** @description Integer - Sets the total number of NFTs returned in the response. Defaults to 100. */ + limit?: number; + /** @description No set timeout by default - When metadata is requested, this parameter is the timeout (in milliseconds) for the website hosting the metadata to respond. If you want to _only_ access the cache and not live fetch any metadata for cache misses then set this value to 0. */ + tokenUriTimeoutInMs?: number; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns a list of NFTs associated with the specified contract address. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description List of objects that represent NFTs stored under the queried contract address. */ + nfts?: { + /** @description The contract object that has details of a contract */ + contract?: { + /** @description Address of the held contract */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description List of reasons why a contract was classified as spam. **Only available on paid tiers.** */ + spamClassifications?: string[]; + }; + /** @default 44 */ + tokenId: string; + tokenType?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Brief human-readable description */ + description?: string; + /** @description Details of the image corresponding to this contract */ + image?: { + /** @description The Url of the image stored in Alchemy cache */ + cachedUrl?: string; + /** @description The Url that has the thumbnail version of the NFT */ + thumbnailUrl?: string; + /** @description The Url that has the NFT image in png */ + pngUrl?: string; + /** @description The Url of the image stored in Alchemy cache */ + contentType?: string; + /** @description The size of the media asset in bytes. */ + size?: number; + /** @description The original Url of the image coming straight from the smart contract */ + originalUrl?: string; + }; + /** @description Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract */ + raw?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually. */ + metadata?: { + /** @description String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces. */ + image?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms) */ + description?: string; + /** @description Object - Traits/attributes/characteristics for each NFT asset. */ + attributes?: { + value?: string; + trait_type?: string; + }[]; + }; + /** @description String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT. */ + error?: string; + }; + /** @description The collection object that has details of a collection */ + collection?: { + /** @description String - Collection name */ + name?: string; + /** @description String - OpenSea collection slug */ + slug?: string; + /** @description String - URL for the external site of the collection */ + externalUrl?: string; + /** @description String - Banner image URL for the collection */ + bannerImageUrl?: string; + }; + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description String - ISO timestamp of the last cache refresh for the information returned in the metadata field. */ + timeLastUpdated?: string; + /** @description Only present if the request specified `orderBy=transferTime`. */ + acquiredAt?: { + /** @description Block timestamp of the block where the NFT was most recently acquired. */ + blockTimestamp?: string; + /** @description Block number of the block where the NFT was most recently acquired. */ + blockNumber?: string; + }; + animation?: { + cachedUrl?: string; + contentType?: string; + size?: number; + orginalUrl?: string; + }; + mint?: { + /** @description Address that minted the NFT */ + mintAddress?: string; + /** @description Block number when the NFT was minted */ + blockNumber?: number; + /** @description Timestamp when the NFT was minted */ + timestamp?: string; + /** @description Transaction hash of the mint transaction */ + transactionHash?: string; + }; + /** @description List of all addresses that own the given NFT. */ + owners?: string[]; + }[]; + /** @description String - An offset used for pagination. Can be passed back as the "startToken" of a subsequent request to get the next page of results. Absent if there are no more results. */ + pageKey?: string; + }; + }; + }; + }; + }; + "getNFTsForCollection-v3": { + parameters: { + query?: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress?: string; + /** @description String - OpenSea slug for the NFT collection. */ + collectionSlug?: string; + /** @description Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. */ + withMetadata?: boolean; + /** @description String - A tokenID offset used for pagination. Can be a hex string, or a decimal. Users can specify the offset themselves to start from a custom offset, or to fetch multiple token ranges in parallel. */ + startToken?: string; + /** @description Integer - Sets the total number of NFTs returned in the response. Defaults to 100. */ + limit?: number; + /** @description No set timeout by default - When metadata is requested, this parameter is the timeout (in milliseconds) for the website hosting the metadata to respond. If you want to _only_ access the cache and not live fetch any metadata for cache misses then set this value to 0. */ + tokenUriTimeoutInMs?: number; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns a list of NFTs associated with the specified collection. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description List of objects that represent NFTs stored under the queried contract address or collection slug. */ + nfts?: { + id?: { + /** @default 44 */ + tokenId: string; + tokenMetadata?: { + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + }; + }; + tokenUri?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + }; + /** @description Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually. */ + metadata?: { + /** @description String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces. */ + image?: string; + /** @description String - The image URL that appears alongside the asset image on NFT platforms. */ + external_url?: string; + /** @description String - Background color of the NFT item. Usually must be defined as a six-character hexadecimal. */ + background_color?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms) */ + description?: string; + /** @description Object - Traits/attributes/characteristics for each NFT asset. */ + attributes?: { + value?: string; + trait_type?: string; + }[]; + media?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + /** @description URL for a resized thumbnail of the NFT media asset. */ + thumbnail?: string; + /** @description The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets. */ + format?: string; + /** @description The size of the media asset in bytes. */ + bytes?: number; + }[]; + }; + /** @description String - ISO timestamp of the last cache refresh for the information returned in the metadata field. */ + timeLastUpdated?: string; + contractMetadata?: { + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + opensea?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + }; + }[]; + /** @description String - An offset used for pagination. Can be passed back as the "startToken" of a subsequent request to get the next page of results. Absent if there are no more results. */ + nextToken?: string; + }; + }; + }; + }; + }; + "getNFTMetadata-v3": { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + /** @description String - The ID of the token. Can be in hex or decimal format. */ + tokenId: string; + /** @description String - 'ERC721' or 'ERC1155'; specifies type of token to query for. API requests will perform faster if this is specified. */ + tokenType?: string; + /** @description No set timeout by default - When metadata is requested, this parameter is the timeout (in milliseconds) for the website hosting the metadata to respond. If you want to _only_ access the cache and not live fetch any metadata for cache misses then set this value to 0. */ + tokenUriTimeoutInMs?: number; + /** @description Defaults to false for faster response times. If true will refresh metadata for given token. If false will check the cache and use it or refresh if cache doesn't exist. */ + refreshCache?: boolean; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns the metadata of the specified NFT. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description The contract object that has details of a contract */ + contract?: { + /** @description Address of the held contract */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description List of reasons why a contract was classified as spam. **Only available on paid tiers.** */ + spamClassifications?: string[]; + }; + /** @default 44 */ + tokenId: string; + tokenType?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Brief human-readable description */ + description?: string; + /** @description Details of the image corresponding to this contract */ + image?: { + /** @description The Url of the image stored in Alchemy cache */ + cachedUrl?: string; + /** @description The Url that has the thumbnail version of the NFT */ + thumbnailUrl?: string; + /** @description The Url that has the NFT image in png */ + pngUrl?: string; + /** @description The Url of the image stored in Alchemy cache */ + contentType?: string; + /** @description The size of the media asset in bytes. */ + size?: number; + /** @description The original Url of the image coming straight from the smart contract */ + originalUrl?: string; + }; + /** @description Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract */ + raw?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually. */ + metadata?: { + /** @description String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces. */ + image?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms) */ + description?: string; + /** @description Object - Traits/attributes/characteristics for each NFT asset. */ + attributes?: { + value?: string; + trait_type?: string; + }[]; + }; + /** @description String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT. */ + error?: string; + }; + /** @description The collection object that has details of a collection */ + collection?: { + /** @description String - Collection name */ + name?: string; + /** @description String - OpenSea collection slug */ + slug?: string; + /** @description String - URL for the external site of the collection */ + externalUrl?: string; + /** @description String - Banner image URL for the collection */ + bannerImageUrl?: string; + }; + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description String - ISO timestamp of the last cache refresh for the information returned in the metadata field. */ + timeLastUpdated?: string; + /** @description Only present if the request specified `orderBy=transferTime`. */ + acquiredAt?: { + /** @description Block timestamp of the block where the NFT was most recently acquired. */ + blockTimestamp?: string; + /** @description Block number of the block where the NFT was most recently acquired. */ + blockNumber?: string; + }; + animation?: { + cachedUrl?: string; + contentType?: string; + size?: number; + orginalUrl?: string; + }; + mint?: { + /** @description Address that minted the NFT */ + mintAddress?: string; + /** @description Block number when the NFT was minted */ + blockNumber?: number; + /** @description Timestamp when the NFT was minted */ + timestamp?: string; + /** @description Transaction hash of the mint transaction */ + transactionHash?: string; + }; + /** @description List of all addresses that own the given NFT. */ + owners?: string[]; + }; + }; + }; + }; + }; + "getNFTMetadataBatch-v3": { + parameters: { + query?: never; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + /** @description List of token objects to batch request NFT metadata for. Maximum 100. */ + tokens: { + /** @default 0xe785E82358879F061BC3dcAC6f0444462D4b5330 */ + contractAddress: string; + /** @default 44 */ + tokenId: string; + tokenType?: string; + }[]; + tokenUriTimeoutInMs?: number; + /** @default false */ + refreshCache?: boolean; + }; + }; + }; + responses: { + /** @description Returns an array of NFT metadata corresponding to the batch query. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description The contract object that has details of a contract */ + contract?: { + /** @description Address of the held contract */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description List of reasons why a contract was classified as spam. **Only available on paid tiers.** */ + spamClassifications?: string[]; + }; + /** @default 44 */ + tokenId: string; + tokenType?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Brief human-readable description */ + description?: string; + /** @description Details of the image corresponding to this contract */ + image?: { + /** @description The Url of the image stored in Alchemy cache */ + cachedUrl?: string; + /** @description The Url that has the thumbnail version of the NFT */ + thumbnailUrl?: string; + /** @description The Url that has the NFT image in png */ + pngUrl?: string; + /** @description The Url of the image stored in Alchemy cache */ + contentType?: string; + /** @description The size of the media asset in bytes. */ + size?: number; + /** @description The original Url of the image coming straight from the smart contract */ + originalUrl?: string; + }; + /** @description Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract */ + raw?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually. */ + metadata?: { + /** @description String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces. */ + image?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms) */ + description?: string; + /** @description Object - Traits/attributes/characteristics for each NFT asset. */ + attributes?: { + value?: string; + trait_type?: string; + }[]; + }; + /** @description String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT. */ + error?: string; + }; + /** @description The collection object that has details of a collection */ + collection?: { + /** @description String - Collection name */ + name?: string; + /** @description String - OpenSea collection slug */ + slug?: string; + /** @description String - URL for the external site of the collection */ + externalUrl?: string; + /** @description String - Banner image URL for the collection */ + bannerImageUrl?: string; + }; + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description String - ISO timestamp of the last cache refresh for the information returned in the metadata field. */ + timeLastUpdated?: string; + /** @description Only present if the request specified `orderBy=transferTime`. */ + acquiredAt?: { + /** @description Block timestamp of the block where the NFT was most recently acquired. */ + blockTimestamp?: string; + /** @description Block number of the block where the NFT was most recently acquired. */ + blockNumber?: string; + }; + animation?: { + cachedUrl?: string; + contentType?: string; + size?: number; + orginalUrl?: string; + }; + mint?: { + /** @description Address that minted the NFT */ + mintAddress?: string; + /** @description Block number when the NFT was minted */ + blockNumber?: number; + /** @description Timestamp when the NFT was minted */ + timestamp?: string; + /** @description Transaction hash of the mint transaction */ + transactionHash?: string; + }; + /** @description List of all addresses that own the given NFT. */ + owners?: string[]; + }[]; + }; + }; + }; + }; + "getContractMetadata-v3": { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns the contract metadata for the specified address. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description String - Contract address for the queried NFT collection */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + }; + }; + }; + }; + }; + "getCollectionMetadata-v3": { + parameters: { + query: { + /** @description String - OpenSea slug for the NFT collection. */ + collectionSlug: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns the collection metadata for the specified slug. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description String - Name of the queried NFT Collection */ + name?: string; + /** @description The human-readable string used to identify the collection on OpenSea. */ + slug?: string; + /** @description Floor price data for the collection */ + floorPrice?: { + /** @description The marketplace the floor price is on */ + marketplace?: string; + /** @description Floor price of the collection on the marketplace */ + floorPrice?: number; + /** @description The currency of the floor price */ + priceCurrency?: string; + }; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + }; + }; + }; + }; + }; + "invalidateContract-v3": { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns confirmation of cache invalidation along with the number of tokens invalidated. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** + * @description True if the contract was invalidated. + * False - if it wasn't. + */ + success?: string; + /** @description The number of tokens that were invalidated as a result of running this query. */ + numTokensInvalidated?: number; + }; + }; + }; + }; + }; + "getContractMetadataBatch-v3": { + parameters: { + query?: never; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + /** + * @description List of contract addresses to batch metadata requests for. + * @default [ + * "0xe785E82358879F061BC3dcAC6f0444462D4b5330", + * "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d" + * ] + */ + contractAddresses?: string[]; + }; + }; + }; + responses: { + /** @description Returns an array of contract metadata corresponding to the batch query. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description String - Contract address for the queried NFT collection */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + }[]; + }; + }; + }; + }; + "getOwnersForNFT-v3": { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + /** @description String - The ID of the token. Can be in hex or decimal format. */ + tokenId: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns the owner(s) of the specified NFT. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description List of all addresses that own the given NFT. */ + owners?: string[]; + pageKey?: string; + }; + }; + }; + }; + }; + "getOwnersForContract-v3": { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + /** @description Boolean - If set to `true` the query will include the token balances per token id for each owner. `false` by default. */ + withTokenBalances?: boolean; + /** @description String - used for contracts with >50,000 owners. `pageKey` field can be passed back as request parameter to get the next page of results. */ + pageKey?: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns a list of all owners for the specified contract. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description List of all addresses that own one of the NFTs from the queried contract address. The format is applicable when `withTokenBalances=true`. */ + owners?: { + /** @default 0xe785E82358879F061BC3dcAC6f0444462D4b5330 */ + ownerAddress: string; + /** @description a list of the token ids and balances for the owner of the collection */ + tokenBalances?: { + /** @description tokenId of the NFT in the collection that an owner has */ + tokenId?: string; + /** @description the number of the specified token in the collection that the user owns */ + balance?: number; + }[]; + }[]; + }; + }; + }; + }; + }; + "getSpamContracts-v3": { + parameters: { + query?: never; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns a list of all spam contracts marked by Alchemy. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description A list of contract addresses earmarked as spam by Alchemy. */ + contractAddresses?: string[]; + }; + }; + }; + }; + }; + "isSpamContract-v3": { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns whether the specified contract is marked as spam. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** + * @description True - if the queried contract is marked as spam. + * False - if the queried contract is considered valid. + */ + isSpamContract?: boolean; + }; + }; + }; + }; + }; + "isAirdropNFT-v3": { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + /** @description String - The ID of the token. Can be in hex or decimal format. */ + tokenId: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns whether the specified token is marked as an airdrop. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** + * @description True - if the queried token is marked as an airdrop. + * False - if the queried token is not marked as an airdrop. + */ + isAirdrop?: boolean; + }; + }; + }; + }; + }; + "summarizeNFTAttributes-v3": { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns a summary of attribute prevalence for the specified NFT collection. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** @description Object mapping trait types to the prevalence of each trait within that type. */ + summary?: Record; + /** @default 0xe785E82358879F061BC3dcAC6f0444462D4b5330 */ + contractAddress: string; + }; + }; + }; + }; + }; + "getFloorPrice-v3": { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + /** @description String - OpenSea slug for the NFT collection. */ + collectionSlug?: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns the floor prices of the specified NFT collection across different marketplaces. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Name of the NFT marketplace where the collection is listed (in camel case). Current marketplaces supported - `openSea`, `looksRare`. So instead of the word `nftMarketplaceName` you will see marketplace names like `openSea` here. */ + nftMarketplaceName?: { + /** @description Number - The floor price of the collection on the given marketplace. */ + floorPrice?: number; + /** + * @description String - The currency in which the floor price is denominated. Typically, denominated in ETH + * @enum {string} + */ + priceCurrency?: "ETH"; + /** @description String - Link to the collection on the given marketplace. */ + collectionUrl?: string; + /** @description String - UTC timestamp of when the floor price was retrieved from the marketplace. */ + retrievedAt?: string; + /** @description String - Returns the error `unable to fetch floor price` if there was an error fetching floor prices from the given marketplace. */ + error?: string; + }; + }; + }; + }; + }; + }; + "searchContractMetadata-v3": { + parameters: { + query: { + /** @description String - The search string that you want to search for in contract metadata */ + query: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns the list of NFT contracts where the metadata has one or more keywords from the search string. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description String - Contract address for the queried NFT collection */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + }[]; + }; + }; + }; + }; + "isHolderOfContract-v3": { + parameters: { + query: { + /** @description String - Wallet address to check for contract ownership. */ + wallet: string; + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns whether the specified wallet holds any NFT from the given contract. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Whether the given wallet owns any token in the given NFT contract. */ + isHolderOfContract?: boolean; + }; + }; + }; + }; + }; + "computeRarity-v3": { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + /** @description String - The ID of the token. Can be in hex or decimal format. */ + tokenId: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns the rarity information for each attribute of the specified NFT. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description NFT attributes and their associated prevalence. */ + rarities?: { + /** @description Name of the trait category, i.e., Hat, Color, Face, etc. */ + trait_type?: string; + /** @description Value for the trait, i.e., White Cap, Blue, Angry, etc. */ + value?: string; + /** @description Floating point value from 0 to 1 representing the prevalence of this value for this trait type. */ + prevalence?: number; + }[]; + }; + }; + }; + }; + }; + "getNFTSales-v3": { + parameters: { + query?: { + /** @description String - The block number to start fetching NFT sales data from. Allowed values are decimal and hex integers, and "latest". Defaults to "0". */ + fromBlock?: string; + /** @description String - The block number to start fetching NFT sales data from. Allowed values are decimal and hex integers, and "latest". Defaults to "latest". */ + toBlock?: string; + /** @description Enum - Whether to return the results ascending from startBlock or descending from startBlock. Defaults to descending (false). */ + order?: "asc" | "desc"; + /** @description Enum - The name of the NFT marketplace to filter sales by. The endpoint currently supports "seaport", "wyvern", "looksrare", "x2y2", "blur", and "cryptopunks". Defaults to returning sales from all supported marketplaces. */ + marketplace?: + | "seaport" + | "looksrare" + | "x2y2" + | "wyvern" + | "blur" + | "cryptopunks"; + /** @description String - The contract address of an NFT collection to filter sales by. Defaults to returning all NFT contracts. */ + contractAddress?: string; + /** @description String - The token ID of an NFT within the collection specified by contractAddress to filter sales by. Defaults to returning all token IDs. */ + tokenId?: string; + /** @description String - The address of the NFT buyer to filter sales by. Defaults to returning sales involving any buyer. */ + buyerAddress?: string; + /** @description String - The address of the NFT seller to filter sales by. Defaults to returning sales involving any seller. */ + sellerAddress?: string; + /** @description Enum - Filter by whether the buyer or seller was the taker in the NFT trade. Allowed filter values are "BUYER" and "SELLER". Defaults to returning both buyer and seller taker trades. */ + taker?: "BUYER" | "SELLER"; + /** @description Integer - The maximum number of NFT sales to return. Maximum and default values are 1000. */ + limit?: number; + /** @description String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results. */ + pageKey?: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns a list of NFT sales that match the query parameters. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description List of NFT sales that match the query. */ + nftSales?: { + /** @description String - The marketplace the sale took place on. */ + marketplace?: string; + /** @description String - The address of the marketplace contract. */ + marketplaceAddress?: string; + /** @description String - The contract address of the collection the NFT belongs to. */ + contractAddress?: string; + /** @description String - The decimal token ID of the NFT being sold. */ + tokenId?: string; + /** @description Integer - The number of tokens sold in the sale as a decimal integer string. */ + quantity?: string; + /** @description String - The address of the buyer in the NFT sale. */ + buyerAddress?: string; + /** @description String - The address of the seller in the NFT sale. */ + sellerAddress?: string; + /** + * @description String - Whether the price taker in the trade was the buyer or the seller. + * @enum {string} + */ + taker?: "BUYER" | "SELLER"; + /** @description The payment from buyer to the seller. */ + sellerFee?: { + /** @description String - The amount of the payment from the buyer to seller as a decimal integer string. */ + amount?: string; + /** @description String - The smart contract address of the token used for the payment. */ + tokenAddress?: string; + /** @description String - The symbol of the token used for the payment. */ + symbol?: string; + /** @description Integer - The number of decimals of the token used for the payment. */ + decimals?: number; + }; + /** @description The payment from buyer to the NFT marketplace protocol. */ + protocolFee?: { + /** @description String - The amount of the payment to the marketplace as a decimal integer string. */ + amount?: string; + /** @description String - The smart contract address of the token used for the payment. */ + tokenAddress?: string; + /** @description String - The symbol of the token used for the payment. */ + symbol?: string; + /** @description Integer - The number of decimals of the token used for the payment. */ + decimals?: number; + }; + /** @description The payment from buyer to the royalty address of the NFT collection. */ + royaltyFee?: { + /** @description String - The amount of the payment to the royalty collector as a decimal integer string. */ + amount?: string; + /** @description String - The smart contract address of the token used for the payment. */ + tokenAddress?: string; + /** @description String - The symbol of the token used for the payment. */ + symbol?: string; + /** @description Integer - The number of decimals of the token used for the payment. */ + decimals?: number; + }; + /** @description Integer - The block number the NFT sale took place in. */ + blockNumber?: number; + /** @description Integer - The log number of the sale event emitted within the block. */ + logIndex?: number; + /** @description Integer - The index of the token within the bundle of NFTs sold in the sale. */ + bundleIndex?: number; + /** @description String - The transaction hash of the transaction containing the sale. */ + transactionHash?: string; + }[]; + /** @description String - The page key to use to fetch the next page of results. Returns null if there are no more results. */ + pageKey?: string; + /** @description Block Information of the block as of which the corresponding data is valid */ + validAt?: { + /** @description The block number above information is valid as of */ + blockNumber?: number; + /** @description The block hash above information is valid as of */ + blockHash?: string; + /** @description The block timestamp above information is valid as of */ + blockTimestamp?: string; + }; + }; + }; + }; + }; + }; + "getContractsForOwner-v3": { + parameters: { + query: { + /** @description String - Address for NFT owner (can be in ENS format for Eth Mainnet). */ + owner: string; + /** @description String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results. */ + pageKey?: string; + /** @description Number of NFTs to be returned per page. Defaults to 100. Max is 100. */ + pageSize?: number; + /** @description Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. */ + withMetadata?: boolean; + /** + * @description Array of filters (as ENUMS) that will be applied to the query. Only NFTs that match one or more of these filters will be included in the response. May not be used in conjunction with excludeFilters[]. Filter Options: + * - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**. + * - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only. + * - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts) + */ + "includeFilters[]"?: ("SPAM" | "AIRDROPS")[]; + /** + * @description Array of filters (as ENUMS) that will be applied to the query. NFTs that match one or more of these filters will be excluded from the response. May not be used in conjunction with includeFilters[]. Filter Options: + * - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**. + * - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only. + * - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts) + */ + "excludeFilters[]"?: ("SPAM" | "AIRDROPS")[]; + /** + * @description Enum - ordering scheme to use for ordering NFTs in the response. If unspecified, NFTs will be ordered by contract address and token ID. + * - transferTime: NFTs will be ordered by the time they were transferred into the wallet, with newest NFTs first. Note: This ordering is supported on Ethereum Mainnet, Optimism Mainnet, Polygon Mainnet, Base Mainnet, Arbitrum One, Polygon Amoy, Base Sepolia, Arbitrum Sepolia, Ethereum Sepolia, and Optimism Sepolia. + */ + orderBy?: "transferTime"; + /** + * @description Enum - the confidence level at which to filter spam at. + * + * Confidence Levels: + * - VERY_HIGH + * - HIGH + * - MEDIUM + * - LOW + * + * The confidence level set means that any spam that is at that confidence level or higher will be filtered out. For example, if the confidence level is HIGH, contracts that we have HIGH or VERY_HIGH confidence in being spam will be filtered out from the response. + * Defaults to VERY_HIGH for Ethereum Mainnet and MEDIUM for Matic Mainnet. + * + * **Please note that this filter is only available on paid tiers. Upgrade your account [here](https://dashboard.alchemy.com/settings/billing/).** + */ + spamConfidenceLevel?: "VERY_HIGH" | "HIGH" | "MEDIUM" | "LOW"; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns a list of NFT contracts held by the specified owner address. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + contracts?: { + /** @default 0xe785E82358879F061BC3dcAC6f0444462D4b5330 */ + address: string; + /** @description The name of the contract, i.e. "Bored Ape Yacht Club". */ + name?: string; + /** @description The symbol of the contract, i.e. BAYC. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + tokenType?: string; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + /** @description Sum of NFT balances across all token IDs held by the owner. For non-fungible tokens this will be equal to the `numDistinctTokensOwned`, but it may be higher if the user holds some fungible ERC1155 tokens. */ + totalBalance?: number; + /** @description Number of distinct token IDs held by the owner. For non-fungible tokens this will be equal to the `totalBalance`, but it may be lower if the user holds some fungible ERC1155 tokens. */ + numDistinctTokensOwned?: number; + /** @description `True` if the contract is detected as spam contract. `False` if it is not spam or has not been evaluated by our system yet */ + isSpam?: boolean; + /** @description Details of the display NFT for this contract. This NFT and its image can be used to represent the contract when displaying info about it. */ + displayNft?: { + /** @description One of the tokens from this contract held by the owner. */ + tokenId?: string; + /** @description The title of the token held by the owner i.e. "Something #22". */ + name?: string; + }; + /** @description Details of the image corresponding to this contract */ + image?: { + /** @description The Url of the image stored in Alchemy cache */ + cachedUrl?: string; + /** @description The Url that has the thumbnail version of the NFT */ + thumbnailUrl?: string; + /** @description The Url that has the NFT image in png */ + pngUrl?: string; + /** @description The Url of the image stored in Alchemy cache */ + contentType?: string; + /** @description The size of the media asset in bytes. */ + size?: number; + /** @description The original Url of the image coming straight from the smart contract */ + originalUrl?: string; + }; + }[]; + pageKey?: string; + /** @description String - Total number of NFT contracts held by the given address returned in this page. */ + totalCount?: string; + }; + }; + }; + }; + }; + "getCollectionsForOwner-v3": { + parameters: { + query: { + /** @description String - Address for NFT owner (can be in ENS format for Eth Mainnet). */ + owner: string; + /** @description String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results. */ + pageKey?: string; + /** @description Number of NFTs to be returned per page. Defaults to 100. Max is 100. */ + pageSize?: number; + /** @description Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. */ + withMetadata?: boolean; + /** + * @description Array of filters (as ENUMS) that will be applied to the query. Only NFTs that match one or more of these filters will be included in the response. May not be used in conjunction with excludeFilters[]. Filter Options: + * - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**. + * - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only. + * - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts) + */ + "includeFilters[]"?: ("SPAM" | "AIRDROPS")[]; + /** + * @description Array of filters (as ENUMS) that will be applied to the query. NFTs that match one or more of these filters will be excluded from the response. May not be used in conjunction with includeFilters[]. Filter Options: + * - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**. + * - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only. + * - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts) + */ + "excludeFilters[]"?: ("SPAM" | "AIRDROPS")[]; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns a list of NFT collections held by the specified owner address. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + collections?: { + /** @description The name of the collection, i.e. "Bored Ape Yacht Club". */ + name?: string; + /** @description The human-readable string used to identify the collection on OpenSea. */ + slug?: string; + /** @description Floor price data for the collection */ + floorPrice?: { + /** @description The marketplace the floor price is on */ + marketplace?: string; + /** @description Floor price of the collection on the marketplace */ + floorPrice?: number; + /** @description The currency of the floor price */ + priceCurrency?: string; + }; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description Contract-level data for a collection, such as contract type, name, and symbol. */ + contract?: { + /** @description Address of the contract */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + }; + /** @description Sum of NFT balances across all token IDs held by the owner. For non-fungible tokens this will be equal to the `numDistinctTokensOwned`, but it may be higher if the user holds some fungible ERC1155 tokens. */ + totalBalance?: number; + /** @description Number of distinct token IDs held by the owner. For non-fungible tokens this will be equal to the `totalBalance`, but it may be lower if the user holds some fungible ERC1155 tokens. */ + numDistinctTokensOwned?: number; + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description Details of the display NFT for this contract. This NFT and its image can be used to represent the contract when displaying info about it. */ + displayNft?: { + /** @description One of the tokens from this contract held by the owner. */ + tokenId?: string; + /** @description The title of the token held by the owner i.e. "Something #22". */ + name?: string; + }; + /** @description Details of the image corresponding to this contract */ + image?: { + /** @description The Url of the image stored in Alchemy cache */ + cachedUrl?: string; + /** @description The Url that has the thumbnail version of the NFT */ + thumbnailUrl?: string; + /** @description The Url that has the NFT image in png */ + pngUrl?: string; + /** @description The Url of the image stored in Alchemy cache */ + contentType?: string; + /** @description The size of the media asset in bytes. */ + size?: number; + /** @description The original Url of the image coming straight from the smart contract */ + originalUrl?: string; + }; + }[]; + pageKey?: string; + /** @description String - Total number of NFT collections held by the given address. */ + totalCount?: string; + }; + }; + }; + }; + }; + "reportSpam-v3": { + parameters: { + query: { + /** @description String - The address to check for spam status. */ + address: string; + isSpam: boolean; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns a confirmation message if the address was successfully reported as spam. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": string; + }; + }; + }; + }; + "refreshNftMetadata-v3": { + parameters: { + query?: never; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + /** + * @description Contract address of the token you want to refresh. + * @default 0xe785E82358879F061BC3dcAC6f0444462D4b5330 + */ + contractAddress: string; + /** + * @description Token ID of the token you want to refresh. Must belong to the contract address. + * @default 44 + */ + tokenId: string; + }; + }; + }; + responses: { + /** @description Returns the status of the refresh request along with the estimated time to complete. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description If the token is successfully queued for ingestion the value will be "Queued". */ + status?: string; + /** @description Estimated time until the metadata refresh is complete for this token. */ + estimatedMsToRefresh?: string; + }; + }; + }; + }; + }; + getNFTs: { + parameters: { + query: { + /** @description String - Address for NFT owner (can be in ENS format for Eth Mainnet). */ + owner: string; + /** @description Array of contract addresses to filter the responses with. Max limit 45 contracts. */ + "contractAddresses[]"?: string[]; + /** @description Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. */ + withMetadata?: boolean; + /** + * @description Enum - ordering scheme to use for ordering NFTs in the response. If unspecified, NFTs will be ordered by contract address and token ID. + * - transferTime: NFTs will be ordered by the time they were transferred into the wallet, with newest NFTs first. Note: This ordering is supported on Ethereum Mainnet, Optimism Mainnet, Polygon Mainnet, Base Mainnet, Arbitrum One, Polygon Amoy, Base Sepolia, Arbitrum Sepolia, Ethereum Sepolia, and Optimism Sepolia. + */ + orderBy?: "transferTime"; + /** + * @description Array of filters (as ENUMS) that will be applied to the query. NFTs that match one or more of these filters will be excluded from the response. May not be used in conjunction with includeFilters[]. Filter Options: + * - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**. + * - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only. + * - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts) + */ + "excludeFilters[]"?: ("SPAM" | "AIRDROPS")[]; + /** + * @description Array of filters (as ENUMS) that will be applied to the query. Only NFTs that match one or more of these filters will be included in the response. May not be used in conjunction with excludeFilters[]. Filter Options: + * - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**. + * - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only. + * - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts) + */ + "includeFilters[]"?: ("SPAM" | "AIRDROPS")[]; + /** + * @description Enum - the confidence level at which to filter spam at. + * + * Confidence Levels: + * - VERY_HIGH + * - HIGH + * - MEDIUM + * - LOW + * + * The confidence level set means that any spam that is at that confidence level or higher will be filtered out. For example, if the confidence level is HIGH, contracts that we have HIGH or VERY_HIGH confidence in being spam will be filtered out from the response. + * Defaults to VERY_HIGH for Ethereum Mainnet and MEDIUM for Matic Mainnet. + * + * **Please note that this filter is only available on paid tiers. Upgrade your account [here](https://dashboard.alchemy.com/settings/billing/).** + */ + spamConfidenceLevel?: "VERY_HIGH" | "HIGH" | "MEDIUM" | "LOW"; + /** @description No set timeout by default - When metadata is requested, this parameter is the timeout (in milliseconds) for the website hosting the metadata to respond. If you want to _only_ access the cache and not live fetch any metadata for cache misses then set this value to 0. */ + tokenUriTimeoutInMs?: number; + /** @description String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results. */ + pageKey?: string; + /** @description Number of NFTs to be returned per page. Defaults to 100. Max is 100. */ + pageSize?: number; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns the list of all NFTs owned by the given address and satisfying the given input parameters. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + ownedNfts?: { + /** @description Object - Contract for returned NFT */ + contract?: { + /** @description String - Address of NFT contract. */ + address?: string; + }; + id?: { + /** @default 44 */ + tokenId: string; + tokenMetadata?: { + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + }; + }; + /** @description String - Token balance */ + balance?: string; + /** @description String - Name of the NFT asset. */ + title?: string; + /** @description String - Brief human-readable description */ + description?: string; + tokenUri?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + }; + media?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + /** @description URL for a resized thumbnail of the NFT media asset. */ + thumbnail?: string; + /** @description The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets. */ + format?: string; + /** @description The size of the media asset in bytes. */ + bytes?: number; + }; + /** @description Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually. */ + metadata?: { + /** @description String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces. */ + image?: string; + /** @description String - The image URL that appears alongside the asset image on NFT platforms. */ + external_url?: string; + /** @description String - Background color of the NFT item. Usually must be defined as a six-character hexadecimal. */ + background_color?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms) */ + description?: string; + /** @description Object - Traits/attributes/characteristics for each NFT asset. */ + attributes?: { + value?: string; + trait_type?: string; + }[]; + media?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + /** @description URL for a resized thumbnail of the NFT media asset. */ + thumbnail?: string; + /** @description The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets. */ + format?: string; + /** @description The size of the media asset in bytes. */ + bytes?: number; + }[]; + }; + /** @description String - ISO timestamp of the last cache refresh for the information returned in the metadata field. */ + timeLastUpdated?: string; + /** @description String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT. */ + error?: string; + contractMetadata?: { + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + opensea?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + }; + /** @description Information about whether and why a contract was marked as spam. */ + spamInfo?: { + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description List of reasons why a contract was classified as spam. **Only available on paid tiers.** */ + spamClassifications?: string[]; + }; + /** @description Only present if the request specified `orderBy=transferTime`. */ + acquiredAt?: { + /** @description Block timestamp of the block where the NFT was most recently acquired. */ + blockTimestamp?: string; + /** @description Block number of the block where the NFT was most recently acquired. */ + blockNumber?: string; + }; + }[]; + pageKey?: string; + /** @description Integer - Total number of NFTs (distinct `tokenIds`) owned by the given address. */ + totalCount?: number; + /** @description String - The canonical head block hash of when your request was received i.e. the block corresponding to `latest` */ + blockHash?: string; + }; + }; + }; + }; + }; + getNFTMetadata: { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + /** @description String - The ID of the token. Can be in hex or decimal format. */ + tokenId: string; + /** @description String - 'ERC721' or 'ERC1155'; specifies type of token to query for. API requests will perform faster if this is specified. */ + tokenType?: string; + /** @description No set timeout by default - When metadata is requested, this parameter is the timeout (in milliseconds) for the website hosting the metadata to respond. If you want to _only_ access the cache and not live fetch any metadata for cache misses then set this value to 0. */ + tokenUriTimeoutInMs?: number; + /** @description Defaults to false for faster response times. If true will refresh metadata for given token. If false will check the cache and use it or refresh if cache doesn't exist. */ + refreshCache?: boolean; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Object - Contract for returned NFT */ + contract?: { + /** @description String - Address of NFT contract. */ + address?: string; + }; + id?: { + /** @default 44 */ + tokenId: string; + tokenMetadata?: { + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + }; + }; + /** @description String - Token balance */ + balance?: string; + /** @description String - Name of the NFT asset. */ + title?: string; + /** @description String - Brief human-readable description */ + description?: string; + tokenUri?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + }; + media?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + /** @description URL for a resized thumbnail of the NFT media asset. */ + thumbnail?: string; + /** @description The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets. */ + format?: string; + /** @description The size of the media asset in bytes. */ + bytes?: number; + }; + /** @description Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually. */ + metadata?: { + /** @description String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces. */ + image?: string; + /** @description String - The image URL that appears alongside the asset image on NFT platforms. */ + external_url?: string; + /** @description String - Background color of the NFT item. Usually must be defined as a six-character hexadecimal. */ + background_color?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms) */ + description?: string; + /** @description Object - Traits/attributes/characteristics for each NFT asset. */ + attributes?: { + value?: string; + trait_type?: string; + }[]; + media?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + /** @description URL for a resized thumbnail of the NFT media asset. */ + thumbnail?: string; + /** @description The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets. */ + format?: string; + /** @description The size of the media asset in bytes. */ + bytes?: number; + }[]; + }; + /** @description String - ISO timestamp of the last cache refresh for the information returned in the metadata field. */ + timeLastUpdated?: string; + /** @description String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT. */ + error?: string; + contractMetadata?: { + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + opensea?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + }; + /** @description Information about whether and why a contract was marked as spam. */ + spamInfo?: { + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description List of reasons why a contract was classified as spam. **Only available on paid tiers.** */ + spamClassifications?: string[]; + }; + /** @description Only present if the request specified `orderBy=transferTime`. */ + acquiredAt?: { + /** @description Block timestamp of the block where the NFT was most recently acquired. */ + blockTimestamp?: string; + /** @description Block number of the block where the NFT was most recently acquired. */ + blockNumber?: string; + }; + }; + }; + }; + }; + }; + getNFTMetadataBatch: { + parameters: { + query?: never; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + /** @description List of token objects to batch request NFT metadata for. Maximum 100. */ + tokens: { + /** @default 0xe785E82358879F061BC3dcAC6f0444462D4b5330 */ + contractAddress: string; + /** @default 44 */ + tokenId: string; + tokenType?: string; + }[]; + tokenUriTimeoutInMs?: number; + /** @default false */ + refreshCache?: boolean; + }; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Object - Contract for returned NFT */ + contract?: { + /** @description String - Address of NFT contract. */ + address?: string; + }; + id?: { + /** @default 44 */ + tokenId: string; + tokenMetadata?: { + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + }; + }; + /** @description String - Token balance */ + balance?: string; + /** @description String - Name of the NFT asset. */ + title?: string; + /** @description String - Brief human-readable description */ + description?: string; + tokenUri?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + }; + media?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + /** @description URL for a resized thumbnail of the NFT media asset. */ + thumbnail?: string; + /** @description The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets. */ + format?: string; + /** @description The size of the media asset in bytes. */ + bytes?: number; + }; + /** @description Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually. */ + metadata?: { + /** @description String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces. */ + image?: string; + /** @description String - The image URL that appears alongside the asset image on NFT platforms. */ + external_url?: string; + /** @description String - Background color of the NFT item. Usually must be defined as a six-character hexadecimal. */ + background_color?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms) */ + description?: string; + /** @description Object - Traits/attributes/characteristics for each NFT asset. */ + attributes?: { + value?: string; + trait_type?: string; + }[]; + media?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + /** @description URL for a resized thumbnail of the NFT media asset. */ + thumbnail?: string; + /** @description The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets. */ + format?: string; + /** @description The size of the media asset in bytes. */ + bytes?: number; + }[]; + }; + /** @description String - ISO timestamp of the last cache refresh for the information returned in the metadata field. */ + timeLastUpdated?: string; + /** @description String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT. */ + error?: string; + contractMetadata?: { + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + opensea?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + }; + /** @description Information about whether and why a contract was marked as spam. */ + spamInfo?: { + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description List of reasons why a contract was classified as spam. **Only available on paid tiers.** */ + spamClassifications?: string[]; + }; + /** @description Only present if the request specified `orderBy=transferTime`. */ + acquiredAt?: { + /** @description Block timestamp of the block where the NFT was most recently acquired. */ + blockTimestamp?: string; + /** @description Block number of the block where the NFT was most recently acquired. */ + blockNumber?: string; + }; + }[]; + }; + }; + }; + }; + getContractMetadata: { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description String - Contract address for the queried NFT collection */ + address?: string; + contractMetadata?: { + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + opensea?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + }; + }; + }; + }; + }; + }; + getContractMetadataBatch: { + parameters: { + query?: never; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + /** + * @description list of contract addresses to batch metadata requests for + * @default [ + * "0xe785E82358879F061BC3dcAC6f0444462D4b5330", + * "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d" + * ] + */ + contractAddresses?: string[]; + }; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @default 0xe785E82358879F061BC3dcAC6f0444462D4b5330 */ + address: string; + /** @description The object that represents a smart contract and has all data corresponding to that contract */ + contractMetadata?: { + /** @description Address of the held contract */ + address?: string; + /** @description Sum of NFT balances across all token IDs held by the owner. For non-fungible tokens this will be equal to the `numDistinctTokensOwned`, but it may be higher if the user holds some fungible ERC1155 tokens. */ + totalBalance?: number; + /** @description Number of distinct token IDs held by the owner. For non-fungible tokens this will be equal to the `totalBalance`, but it may be lower if the user holds some fungible ERC1155 tokens. */ + numDistinctTokensOwned?: number; + isSpam?: boolean; + /** @description One of the tokens from this contract held by the owner. */ + tokenId?: string; + /** @description The name of the contract, i.e. "Bored Ape Yacht Club". */ + name?: string; + /** @description The title of the token held by the owner i.e. "Something #22". */ + title?: string; + /** @description The symbol of the contract, i.e. BAYC. */ + symbol?: string; + /** @description The NFT standard used by the contract, i.e. ERC721 or ERC1155. */ + tokenType?: string; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + media?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + /** @description URL for a resized thumbnail of the NFT media asset. */ + thumbnail?: string; + /** @description The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets. */ + format?: string; + /** @description The size of the media asset in bytes. */ + bytes?: number; + }[]; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + opensea?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + }; + }[]; + }; + }; + }; + }; + getNFTsForCollection: { + parameters: { + query?: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress?: string; + /** @description String - OpenSea slug for the NFT collection. */ + collectionSlug?: string; + /** @description Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. */ + withMetadata?: boolean; + /** @description String - A tokenID offset used for pagination. Can be a hex string, or a decimal. Users can specify the offset themselves to start from a custom offset, or to fetch multiple token ranges in parallel. */ + startToken?: string; + /** @description Integer - Sets the total number of NFTs returned in the response. Defaults to 100. */ + limit?: number; + /** @description No set timeout by default - When metadata is requested, this parameter is the timeout (in milliseconds) for the website hosting the metadata to respond. If you want to _only_ access the cache and not live fetch any metadata for cache misses then set this value to 0. */ + tokenUriTimeoutInMs?: number; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description List of objects that represent NFTs stored under the queried contract address or collection slug. */ + nfts?: { + id?: { + /** @default 44 */ + tokenId: string; + tokenMetadata?: { + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + }; + }; + tokenUri?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + }; + /** @description Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually. */ + metadata?: { + /** @description String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces. */ + image?: string; + /** @description String - The image URL that appears alongside the asset image on NFT platforms. */ + external_url?: string; + /** @description String - Background color of the NFT item. Usually must be defined as a six-character hexadecimal. */ + background_color?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms) */ + description?: string; + /** @description Object - Traits/attributes/characteristics for each NFT asset. */ + attributes?: { + value?: string; + trait_type?: string; + }[]; + media?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + /** @description URL for a resized thumbnail of the NFT media asset. */ + thumbnail?: string; + /** @description The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets. */ + format?: string; + /** @description The size of the media asset in bytes. */ + bytes?: number; + }[]; + }; + /** @description String - ISO timestamp of the last cache refresh for the information returned in the metadata field. */ + timeLastUpdated?: string; + contractMetadata?: { + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + opensea?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + }; + }[]; + /** @description String - An offset used for pagination. Can be passed back as the "startToken" of a subsequent request to get the next page of results. Absent if there are no more results. */ + nextToken?: string; + }; + }; + }; + }; + }; + getOwnersForToken: { + parameters: { + query: { + /** @description String - Contract address for the token to get the owner for. */ + contractAddress: string; + /** @description String - The ID of the token. Can be in hex or decimal format. */ + tokenId: string; + /** @description String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results. */ + pageKey?: string; + /** @description Number of owners to be returned per page. */ + pageSize?: number; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description List of all addresses that own the given NFT. */ + owners?: string[]; + }; + }; + }; + }; + }; + getOwnersForCollection: { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + /** @description Boolean - If set to `true` the query will include the token balances per token id for each owner. `false` by default. */ + withTokenBalances?: boolean; + /** @description String - used for collections with >50,000 owners. `pageKey` field can be passed back as request parameter to get the next page of results. */ + pageKey?: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": string[]; + }; + }; + }; + }; + getSpamContracts: { + parameters: { + query?: never; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description A list of contract addresses earmarked as spam by Alchemy. */ + contractAddresses?: string[]; + }; + }; + }; + }; + }; + isSpamContract: { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": boolean; + }; + }; + }; + }; + isAirdrop: { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + /** @description String - The ID of the token. Can be in hex or decimal format. */ + tokenId: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": boolean; + }; + }; + }; + }; + invalidateContract: { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** + * @description True if the contract was invalidated. + * False - if it wasn't. + */ + success?: string; + /** @description The number of tokens that were invalidated as a result of running this query. */ + numTokensInvalidated?: number; + }; + }; + }; + }; + }; + getFloorPrice: { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Name of the NFT marketplace where the collection is listed. Current marketplaces supported - OpenSea, LooksRare */ + nftMarketplace?: { + /** @description Number - The floor price of the collection on the given marketplace. */ + floorPrice?: number; + /** + * @description String - The currency in which the floor price is denominated. Typically, denominated in ETH + * @enum {string} + */ + priceCurrency?: "ETH"; + /** @description String - Link to the collection on the given marketplace. */ + collectionUrl?: string; + /** @description String - UTC timestamp of when the floor price was retrieved from the marketplace. */ + retrievedAt?: string; + /** @description String - Returns an error if there was an error fetching floor prices from the given marketplace. */ + error?: string; + }; + }; + }; + }; + }; + }; + computeRarity: { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + /** @description String - The ID of the token. Can be in hex or decimal format. */ + tokenId: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description NFT attributes and their associated prevalence. */ + rarities?: { + /** @description Name of the trait category, i.e. Hat, Color, Face, etc. */ + trait_type?: string; + /** @description Value for the trait, i.e. White Cap, Blue, Angry, etc. */ + value?: string; + /** @description Floating point value from 0 to 1 representing the prevalence of this value for this trait type. */ + prevalence?: number; + }[]; + }; + }; + }; + }; + }; + searchContractMetadata: { + parameters: { + query: { + /** @description String - The search string that you want to search for in contract metadata */ + query: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns the list of NFT contracts where the metadata has one or more keywords from the search string. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @default 0xe785E82358879F061BC3dcAC6f0444462D4b5330 */ + address: string; + contractMetadata?: { + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + opensea?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + }; + }[]; + }; + }; + }; + }; + summarizeNFTAttributes: { + parameters: { + query: { + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** @description Object mapping trait types to the prevalence of each trait within that type. */ + summary?: Record; + /** @default 0xe785E82358879F061BC3dcAC6f0444462D4b5330 */ + contractAddress: string; + }; + }; + }; + }; + }; + isHolderOfCollection: { + parameters: { + query: { + /** @description String - Address for NFT owner (can be in ENS format for Eth Mainnet). */ + wallet: string; + /** @description String - Contract address for the NFT contract (ERC721 and ERC1155 supported). */ + contractAddress: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Whether the given wallet owns any token in the given NFT collection. */ + isHolderOfCollection?: boolean; + }; + }; + }; + }; + }; + getNFTSales: { + parameters: { + query?: { + /** @description String - The block number to start fetching NFT sales data from. Allowed values are decimal and hex integers, and "latest". Defaults to "0". */ + fromBlock?: string; + /** @description String - The block number to start fetching NFT sales data from. Allowed values are decimal and hex integers, and "latest". Defaults to "latest". */ + toBlock?: string; + /** @description Enum - Whether to return the results ascending from startBlock or descending from startBlock. Defaults to descending (false). */ + order?: "asc" | "desc"; + /** @description Enum - The name of the NFT marketplace to filter sales by. The endpoint currently supports "seaport", "wyvern", "looksrare", "x2y2", "blur", and "cryptopunks". Defaults to returning sales from all supported marketplaces. */ + marketplace?: + | "seaport" + | "looksrare" + | "x2y2" + | "wyvern" + | "blur" + | "cryptopunks"; + /** @description String - The contract address of a NFT collection to filter sales by. Defaults to returning all NFT contracts. */ + contractAddress?: string; + /** @description String - The token ID of an NFT within the collection specified by contractAddress to filter sales by. Defaults to returning all token IDs. */ + tokenId?: string; + /** @description String - The address of the NFT buyer to filter sales by. Defaults to returning sales involving any buyer. */ + buyerAddress?: string; + /** @description String - The address of the NFT seller to filter sales by. Defaults to returning sales involving any seller. */ + sellerAddress?: string; + /** @description Enum - Filter by whether the buyer or seller was the taker in the NFT trade. Allowed filter values are "BUYER" and "SELLER". Defaults to returning both buyer and seller taker trades. */ + taker?: "BUYER" | "SELLER"; + /** @description Integer - The maximum number of NFT sales to return. Maximum and default values are 1000. */ + limit?: number; + /** @description String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results. */ + pageKey?: string; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description List of NFT sales that match the query */ + nftSales?: { + /** @description String - The marketplace the sale took place on. */ + marketplace?: string; + /** @description String - The contract address of the collection the NFT belongs to. */ + contractAddress?: string; + /** @description String - The decimal token ID of the NFT being sold. */ + tokenId?: string; + /** @description Integer - The number of tokens sold in the sale as a decimal integer string. */ + quantity?: string; + /** @description String - The address of the buyer in the NFT sale. */ + buyerAddress?: string; + /** @description String - The address of the seller in the NFT sale. */ + sellerAddress?: string; + /** + * @description String - Whether the price taker in the trade was the buyer or the seller. + * @enum {string} + */ + taker?: "BUYER" | "SELLER"; + /** @description The payment from buyer to the seller */ + sellerFee?: { + /** @description String - The amount of the payment from the buyer to seller as a decimal integer string. */ + amount?: string; + /** @description String - The symbol of the token used for the payment. */ + symbol?: string; + /** @description Integer - The number of decimals of the token used for the payment. */ + decimals?: number; + }; + /** @description The payment from buyer to the NFT marketplace protocol */ + protocolFee?: { + /** @description String - The amount of the payment to the marketplace as a decimal integer string. */ + amount?: string; + /** @description String - The symbol of the token used for the payment. */ + symbol?: string; + /** @description Integer - The number of decimals of the token used for the payment. */ + decimals?: number; + }; + /** @description The payment from buyer to the royalty address of the NFT collection */ + royaltyFee?: { + /** @description String - The amount of the payment to the royalty collector as a decimal integer string. */ + amount?: string; + /** @description String - The symbol of the token used for the payment. */ + symbol?: string; + /** @description Integer - The number of decimals of the token used for the payment. */ + decimals?: number; + }; + /** @description Integer - The block number the NFT sale took place in. */ + blockNumber?: number; + /** @description Integer - The log number of the sale event emitted within the block. */ + logIndex?: number; + /** @description Integer - The index of the token within the bundle of NFTs sold in the sale. */ + bundleIndex?: number; + /** @description String - The transaction hash of the transaction containing the sale. */ + transactionHash?: string; + }[]; + /** @description String - The page key to use to fetch the next page of results. Returns null if there are no more results. */ + pageKey?: string; + }; + }; + }; + }; + }; + getContractsForOwner: { + parameters: { + query: { + /** @description String - Address for NFT owner (can be in ENS format for Eth Mainnet). */ + owner: string; + /** @description String - key for pagination. If more results are available, a pageKey will be returned in the response. Pass back the pageKey as a param to fetch the next page of results. */ + pageKey?: string; + /** @description Number of NFTs to be returned per page. Defaults to 100. Max is 100. */ + pageSize?: number; + /** @description Boolean - if set to `true`, returns NFT metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. */ + withMetadata?: boolean; + /** + * @description Array of filters (as ENUMS) that will be applied to the query. Only NFTs that match one or more of these filters will be included in the response. May not be used in conjunction with excludeFilters[]. Filter Options: + * - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**. + * - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only. + * - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts) + */ + "includeFilters[]"?: ("SPAM" | "AIRDROPS")[]; + /** + * @description Array of filters (as ENUMS) that will be applied to the query. NFTs that match one or more of these filters will be excluded from the response. May not be used in conjunction with includeFilters[]. Filter Options: + * - SPAM: NFTs that have been classified as spam. Spam classification has a wide range of criteria that includes but is not limited to emitting fake events and copying other well-known NFTs. Please note that this filter is currently supported on Mainnet for Base, Arbitrum, Optimism, Ethereum, Polygon, Worldchain, Avax, BNB, Gnosis, Zksync, Unichain, and Blast, and is **available exclusively on paid tiers**. + * - AIRDROPS: NFTs that have were airdropped to the user. Airdrops are defined as NFTs that were minted to a user address in a transaction sent by a different address. NOTE: this filter is currently supported on Ethereum Mainnet, Ethereum Goerli, and Matic Mainnet only. + * - To learn more about spam, you can refer to this: [Spam NFTs and how to fix them](https://www.alchemy.com/overviews/spam-nfts) + */ + "excludeFilters[]"?: ("SPAM" | "AIRDROPS")[]; + /** + * @description Enum - ordering scheme to use for ordering NFTs in the response. If unspecified, NFTs will be ordered by contract address and token ID. + * - transferTime: NFTs will be ordered by the time they were transferred into the wallet, with newest NFTs first. Note: This ordering is supported on Ethereum Mainnet, Optimism Mainnet, Polygon Mainnet, Base Mainnet, Arbitrum One, Polygon Amoy, Base Sepolia, Arbitrum Sepolia, Ethereum Sepolia, and Optimism Sepolia. + */ + orderBy?: "transferTime"; + /** + * @description Enum - the confidence level at which to filter spam at. + * + * Confidence Levels: + * - VERY_HIGH + * - HIGH + * - MEDIUM + * - LOW + * + * The confidence level set means that any spam that is at that confidence level or higher will be filtered out. For example, if the confidence level is HIGH, contracts that we have HIGH or VERY_HIGH confidence in being spam will be filtered out from the response. + * Defaults to VERY_HIGH for Ethereum Mainnet and MEDIUM for Matic Mainnet. + * + * **Please note that this filter is only available on paid tiers. Upgrade your account [here](https://dashboard.alchemy.com/settings/billing/).** + */ + spamConfidenceLevel?: "VERY_HIGH" | "HIGH" | "MEDIUM" | "LOW"; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + contracts?: { + /** @description Address of the held contract */ + address?: string; + /** @description Sum of NFT balances across all token IDs held by the owner. For non-fungible tokens this will be equal to the `numDistinctTokensOwned`, but it may be higher if the user holds some fungible ERC1155 tokens. */ + totalBalance?: number; + /** @description Number of distinct token IDs held by the owner. For non-fungible tokens this will be equal to the `totalBalance`, but it may be lower if the user holds some fungible ERC1155 tokens. */ + numDistinctTokensOwned?: number; + isSpam?: boolean; + /** @description One of the tokens from this contract held by the owner. */ + tokenId?: string; + /** @description The name of the contract, i.e. "Bored Ape Yacht Club". */ + name?: string; + /** @description The title of the token held by the owner i.e. "Something #22". */ + title?: string; + /** @description The symbol of the contract, i.e. BAYC. */ + symbol?: string; + /** @description The NFT standard used by the contract, i.e. ERC721 or ERC1155. */ + tokenType?: string; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + media?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + raw?: string; + /** @description String - Public gateway uri for the raw uri above. */ + gateway?: string; + /** @description URL for a resized thumbnail of the NFT media asset. */ + thumbnail?: string; + /** @description The media format (jpg, gif, png, etc.) of the gateway and thumbnail assets. */ + format?: string; + /** @description The size of the media asset in bytes. */ + bytes?: number; + }[]; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + opensea?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + }[]; + pageKey?: string; + /** @description String - Total number of NFT contracts held by the given address returned in this page. */ + totalCount?: string; + }; + }; + }; + }; + }; + reportSpam: { + parameters: { + query: { + /** @description String - The address to check for spam status. */ + address: string; + /** @description Boolean - Whether the address is spam. */ + isSpam: boolean; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": string; + }; + }; + }; + }; +} diff --git a/packages/data-apis/src/generated/rest/portfolio.schema.ts b/packages/data-apis/src/generated/rest/portfolio.schema.ts new file mode 100644 index 0000000000..9a41ff79c4 --- /dev/null +++ b/packages/data-apis/src/generated/rest/portfolio.schema.ts @@ -0,0 +1,31 @@ +/* eslint-disable -- machine-generated file */ +// AUTO-GENERATED by @alchemy/api-codegen — DO NOT EDIT. +// Regenerate with `pnpm generate`. Spec provenance (docs repo commit + checksums) +// is recorded in packages/api-codegen/specs/specs.lock.json. + +import type { RestRequestSchema } from "@alchemy/common"; +import type { operations } from "./portfolio.types.js"; + +/** Request body for get-tokens-by-address. */ +export type GetTokensByAddressBody = NonNullable< + operations["get-tokens-by-address"]["requestBody"] +>["content"]["application/json"]; + +/** 200 response for get-tokens-by-address. */ +export type GetTokensByAddressResponse = + operations["get-tokens-by-address"]["responses"]["200"]["content"]["application/json"]; + +/** RestRequestSchema entries for the portfolio REST API. */ +export type PortfolioRestSchema = readonly [ + { + /** POST /{apiKey}/assets/tokens/by-address (operationId: get-tokens-by-address) */ + Route: "assets/tokens/by-address"; + Method: "POST"; + Body: GetTokensByAddressBody; + Response: GetTokensByAddressResponse; + }, +]; + +/** Compile-time guard that the emitted tuple satisfies the shared constraint. */ +export type _AssertPortfolioRestSchema = + PortfolioRestSchema extends RestRequestSchema ? true : never; diff --git a/packages/data-apis/src/generated/rest/portfolio.types.ts b/packages/data-apis/src/generated/rest/portfolio.types.ts new file mode 100644 index 0000000000..5cacfec454 --- /dev/null +++ b/packages/data-apis/src/generated/rest/portfolio.types.ts @@ -0,0 +1,1719 @@ +/* eslint-disable -- machine-generated file */ +// AUTO-GENERATED by @alchemy/api-codegen — DO NOT EDIT. +// Regenerate with `pnpm generate`. Spec provenance (docs repo commit + checksums) +// is recorded in packages/api-codegen/specs/specs.lock.json. + +export interface paths { + "/{apiKey}/assets/tokens/by-address": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Tokens By Wallet + * @description Fetches fungible tokens (native, ERC-20 and SPL) for multiple wallet addresses and networks. Returns a list of tokens with balances, prices, and metadata for each wallet/network combination. This endpoint is supported on Ethereum, Solana, and 30+ EVM chains. See the full list of supported networks [here](https://dashboard.alchemy.com/chains). + */ + post: operations["get-tokens-by-address"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/{apiKey}/assets/tokens/balances/by-address": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Token Balances By Wallet + * @description Fetches fungible tokens (native, ERC-20, and SPL) for multiple wallet addresses and networks. Returns a list of tokens with balances for each wallet/network combination. This endpoint is supported on Ethereum, Solana, and 30+ EVM chains. See the full list of supported networks [here](https://dashboard.alchemy.com/chains) + */ + post: operations["get-token-balances-by-address"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/{apiKey}/assets/nfts/by-address": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * NFTs By Wallet + * @description Fetches NFTs for multiple wallet addresses and networks. Returns a list of NFTs and metadata for each wallet/network combination. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains). + */ + post: operations["get-nfts-by-address"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/{apiKey}/assets/nfts/contracts/by-address": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * NFT Collections By Wallet + * @description Fetches NFT collections (contracts) for multiple wallet addresses and networks. Returns a list of collections and metadata for each wallet/network combination. This endpoint is supported on Ethereum and many L2s, including Polygon, Arbitrum, Optimism, Base, World Chain and more. See the full list of supported networks [here](https://dashboard.alchemy.com/chains). + */ + post: operations["get-nft-contracts-by-address"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; +} +export type webhooks = Record; +export interface components { + schemas: { + ByAddressRequest: { + /** @description Array of wallet addresses and the networks to query them on. Maximum 2 addresses and maximum 5 networks per address. */ + addresses: { + /** + * @description Wallet address. + * @default 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + * @example 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + */ + address: string; + /** + * @description Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains) + * @default [ + * "eth-mainnet", + * "base-mainnet", + * "matic-mainnet" + * ] + */ + networks: string[]; + }[]; + }; + ByAddressRequestWith1AddressAnd2Networks: { + /** @description Array of address and networks pairs (limit 1 pairs, max 2 networks). Networks should match network enums. */ + addresses: { + /** + * @description Wallet address. + * @default 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + * @example 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + */ + address: string; + /** + * @description (In BETA and only accepts ETH & BASE mainnets). Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains) + * @default [ + * "eth-mainnet", + * "base-mainnet" + * ] + */ + networks: string[]; + }[]; + /** @description The cursor that points to the previous set of results. */ + before?: string; + /** @description The cursor that points to the end of the current set of results. */ + after?: string; + /** + * @description Sets the maximum number of items per page (Max: 50) + * @default 25 + */ + limit: number; + pageKey?: string; + }; + ByAddressRequestWith3PairsAnd20Networks: { + /** @description Array of address and networks pairs (limit 3 pairs, max 20 networks). Networks should match network enums. */ + addresses: { + /** + * @description Wallet address. + * @default 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + * @example 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + */ + address: string; + /** + * @description Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains) + * @default [ + * "eth-mainnet", + * "base-mainnet", + * "matic-mainnet" + * ] + */ + networks: string[]; + }[]; + /** + * @description Whether to include each chain's native token in the response (e.g. ETH on Ethereum). The native token will have a null contract address. + * @default true + * @example true + */ + includeNativeTokens: boolean; + /** + * @description Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @default true + */ + includeErc20Tokens: boolean; + }; + ByAddressRequestWithOptions: { + /** @description Array of wallet addresses and the networks to query them on. Maximum 2 addresses and maximum 5 networks per address. */ + addresses: { + /** + * @description Wallet address. + * @default 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + * @example 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + */ + address: string; + /** + * @description Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains) + * @default [ + * "eth-mainnet", + * "base-mainnet", + * "matic-mainnet" + * ] + */ + networks: string[]; + }[]; + /** + * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @default true + */ + withMetadata: boolean; + /** + * @description Boolean - if set to `true`, returns token prices. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @default true + */ + withPrices: boolean; + /** + * @description Whether to include each chain's native token in the response (e.g. ETH on Ethereum). The native token will have a null contract address. + * @default true + * @example true + */ + includeNativeTokens: boolean; + /** + * @description Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @default true + */ + includeErc20Tokens: boolean; + }; + ByAddressRequestWithNFTOptionsAndPaging: { + /** @description Array of address and networks pairs (limit 2 pairs, max 15 networks each). Networks should match network enums. */ + addresses: { + /** + * @description Wallet address. + * @default 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + * @example 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + */ + address: string; + /** + * @description Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains) + * @default [ + * "eth-mainnet", + * "base-mainnet", + * "matic-mainnet" + * ] + */ + networks: ( + | "eth-mainnet" + | "eth-sepolia" + | "eth-holesky" + | "avax-mainnet" + | "avax-fuji" + | "zksync-mainnet" + | "opt-mainnet" + | "polygon-mainnet" + | "polygon-amoy" + | "arb-mainnet" + | "arb-sepolia" + | "blast-mainnet" + | "blast-sepolia" + | "base-mainnet" + | "base-sepolia" + | "soneium-mainnet" + | "soneium-minato" + | "scroll-mainnet" + | "scroll-sepolia" + | "shape-mainnet" + | "shape-sepolia" + | "lens-mainnet" + | "lens-sepolia" + | "starknet-mainnet" + | "starknet-sepolia" + | "rootstock-mainnet" + | "rootstock-testnet" + | "linea-mainnet" + | "linea-sepolia" + | "settlus-septestnet" + | "abstract-mainnet" + | "abstract-testnet" + | "apechain-mainnet" + )[]; + excludeFilters?: ("SPAM" | "AIRDROPS")[]; + includeFilters?: ("SPAM" | "AIRDROPS")[]; + /** @enum {string} */ + spamConfidenceLevel?: "VERY_HIGH" | "HIGH" | "MEDIUM" | "LOW"; + }[]; + /** + * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @default true + */ + withMetadata: boolean; + pageKey?: string; + /** @default 100 */ + pageSize: number; + }; + ByAddressRequestWithNFTOptions: { + /** @description Array of wallet addresses and the networks to query them on. Maximum 2 addresses and maximum 5 networks per address. */ + addresses: { + /** + * @description Wallet address. + * @default 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + * @example 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + */ + address: string; + /** + * @description Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains) + * @default [ + * "eth-mainnet", + * "base-mainnet", + * "matic-mainnet" + * ] + */ + networks: string[]; + }[]; + /** + * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @default true + */ + withMetadata: boolean; + }; + AddressItemForNFTOwnership: { + /** + * @description Wallet address. + * @default 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + * @example 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + */ + address: string; + /** + * @description Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains) + * @default [ + * "eth-mainnet", + * "base-mainnet", + * "matic-mainnet" + * ] + */ + networks: ( + | "eth-mainnet" + | "eth-sepolia" + | "eth-holesky" + | "avax-mainnet" + | "avax-fuji" + | "zksync-mainnet" + | "opt-mainnet" + | "polygon-mainnet" + | "polygon-amoy" + | "arb-mainnet" + | "arb-sepolia" + | "blast-mainnet" + | "blast-sepolia" + | "base-mainnet" + | "base-sepolia" + | "soneium-mainnet" + | "soneium-minato" + | "scroll-mainnet" + | "scroll-sepolia" + | "shape-mainnet" + | "shape-sepolia" + | "lens-mainnet" + | "lens-sepolia" + | "starknet-mainnet" + | "starknet-sepolia" + | "rootstock-mainnet" + | "rootstock-testnet" + | "linea-mainnet" + | "linea-sepolia" + | "settlus-septestnet" + | "abstract-mainnet" + | "abstract-testnet" + | "apechain-mainnet" + )[]; + excludeFilters?: ("SPAM" | "AIRDROPS")[]; + includeFilters?: ("SPAM" | "AIRDROPS")[]; + /** @enum {string} */ + spamConfidenceLevel?: "VERY_HIGH" | "HIGH" | "MEDIUM" | "LOW"; + }; + TokensResponse: { + /** @description List of tokens by address, with prices and metadata. */ + data: { + tokens?: { + /** @description Wallet address. */ + address: string; + /** @description Network identifier. */ + network: string; + /** @description Token address. */ + tokenAddress: string; + /** @description Balance of that particular token. */ + tokenBalance: string; + tokenMetadata?: { + /** @description Number of decimals the token uses */ + decimals?: number; + /** @description URL of the token's logo image */ + logo?: string; + /** @description Token's name */ + name?: string; + /** @description Token's symbol */ + symbol?: string; + }; + /** @description List of price information. */ + tokenPrices?: { + /** @example usd */ + currency: string; + /** @example 4608.2208671202 */ + value: string; + /** + * Format: date-time + * @example 2025-08-26T20:17:27Z + */ + lastUpdatedAt: string; + }[]; + /** @description Error message if applicable. */ + error?: string | null; + }[]; + pageKey?: string; + }; + }; + TokenBalancesResponse: { + data: { + /** @description List of token balances by address. */ + tokens?: { + /** @description Network identifier. */ + network: string; + /** @description Wallet address. */ + address: string; + /** @description Token address. */ + tokenAddress: string; + /** @description Balance of that particular token. */ + tokenBalance: string; + }[]; + pageKey?: string; + }; + }; + NFTByOwnerResponse: { + /** @description List of nfts by address with appropriate metadata. */ + data: { + ownedNfts?: { + /** @description Network identifier. */ + network?: string; + /** @description Wallet address. */ + address?: string; + /** @description The contract object that has details of a contract */ + contract?: { + /** @description Address of the held contract */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description List of reasons why a contract was classified as spam. **Only available on paid tiers.** */ + spamClassifications?: string[]; + }; + /** @default 44 */ + tokenId: string; + tokenType?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Brief human-readable description */ + description?: string; + /** @description Details of the image corresponding to this contract */ + image?: { + /** @description The Url of the image stored in Alchemy cache */ + cachedUrl?: string; + /** @description The Url that has the thumbnail version of the NFT */ + thumbnailUrl?: string; + /** @description The Url that has the NFT image in png */ + pngUrl?: string; + /** @description The Url of the image stored in Alchemy cache */ + contentType?: string; + /** @description The size of the media asset in bytes. */ + size?: number; + /** @description The original Url of the image coming straight from the smart contract */ + originalUrl?: string; + }; + /** @description Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract */ + raw?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually. */ + metadata?: { + /** @description String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces. */ + image?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms) */ + description?: string; + /** @description Object - Traits/attributes/characteristics for each NFT asset. */ + attributes?: { + value?: string; + trait_type?: string; + }[]; + }; + /** @description String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT. */ + error?: string; + }; + /** @description The collection object that has details of a collection */ + collection?: { + /** @description String - Collection name */ + name?: string; + /** @description String - OpenSea collection slug */ + slug?: string; + /** @description String - URL for the external site of the collection */ + externalUrl?: string; + /** @description String - Banner image URL for the collection */ + bannerImageUrl?: string; + }; + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description String - ISO timestamp of the last cache refresh for the information returned in the metadata field. */ + timeLastUpdated?: string; + /** @description Only present if the request specified `orderBy=transferTime`. */ + acquiredAt?: { + /** @description Block timestamp of the block where the NFT was most recently acquired. */ + blockTimestamp?: string; + /** @description Block number of the block where the NFT was most recently acquired. */ + blockNumber?: string; + }; + }[]; + /** @description Integer - Total number of NFTs (distinct `tokenIds`) owned by the given address. */ + totalCount?: number; + pageKey?: string; + }; + }; + NFTCollectionsByOwnerResponse: { + /** @description List of nft collections. */ + data: { + contracts?: { + /** @description Network identifier. */ + network?: string; + /** @description Wallet address. */ + address?: string; + /** @description The contract object that has details of a contract */ + contract?: { + /** @description Address of the held contract */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description List of reasons why a contract was classified as spam. **Only available on paid tiers.** */ + spamClassifications?: string[]; + }; + }[]; + /** @description Integer - Total number of NFTs (distinct `tokenIds`) owned by the given address. */ + totalCount?: number; + pageKey?: string; + }; + }; + /** @description The object that represents an NFT and has all data corresponding to that NFT */ + NFTResponseItem: { + /** @description Network identifier. */ + network?: string; + /** @description Wallet address. */ + address?: string; + /** @description The contract object that has details of a contract */ + contract?: { + /** @description Address of the held contract */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description List of reasons why a contract was classified as spam. **Only available on paid tiers.** */ + spamClassifications?: string[]; + }; + /** @default 44 */ + tokenId: string; + tokenType?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Brief human-readable description */ + description?: string; + /** @description Details of the image corresponding to this contract */ + image?: { + /** @description The Url of the image stored in Alchemy cache */ + cachedUrl?: string; + /** @description The Url that has the thumbnail version of the NFT */ + thumbnailUrl?: string; + /** @description The Url that has the NFT image in png */ + pngUrl?: string; + /** @description The Url of the image stored in Alchemy cache */ + contentType?: string; + /** @description The size of the media asset in bytes. */ + size?: number; + /** @description The original Url of the image coming straight from the smart contract */ + originalUrl?: string; + }; + /** @description Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract */ + raw?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually. */ + metadata?: { + /** @description String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces. */ + image?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms) */ + description?: string; + /** @description Object - Traits/attributes/characteristics for each NFT asset. */ + attributes?: { + value?: string; + trait_type?: string; + }[]; + }; + /** @description String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT. */ + error?: string; + }; + /** @description The collection object that has details of a collection */ + collection?: { + /** @description String - Collection name */ + name?: string; + /** @description String - OpenSea collection slug */ + slug?: string; + /** @description String - URL for the external site of the collection */ + externalUrl?: string; + /** @description String - Banner image URL for the collection */ + bannerImageUrl?: string; + }; + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description String - ISO timestamp of the last cache refresh for the information returned in the metadata field. */ + timeLastUpdated?: string; + /** @description Only present if the request specified `orderBy=transferTime`. */ + acquiredAt?: { + /** @description Block timestamp of the block where the NFT was most recently acquired. */ + blockTimestamp?: string; + /** @description Block number of the block where the NFT was most recently acquired. */ + blockNumber?: string; + }; + }; + /** @description The object that represents an NFT collection */ + NFTCollectionResponseItem: { + /** @description Network identifier. */ + network?: string; + /** @description Wallet address. */ + address?: string; + /** @description The contract object that has details of a contract */ + contract?: { + /** @description Address of the held contract */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description List of reasons why a contract was classified as spam. **Only available on paid tiers.** */ + spamClassifications?: string[]; + }; + }; + TransactionHistoryResponse: { + /** @description The cursor that points to the previous set of results. */ + before?: string; + /** @description The cursor that points to the end of the current set of results. */ + after?: string; + /** @description Total count of the response items. */ + totalCount?: number; + /** @description List of transactions by address. */ + transactions: { + /** @description Network associated with an individual transaction */ + network?: string; + /** @description Transaction hash */ + hash?: string; + /** @description (ISO 8601) Timestamp of transaction mining / confirmation */ + timeStamp?: string; + /** @description Block number of transaction mining / confirmation */ + blockNumber?: number; + /** @description Block hash of transaction mining / confirmation */ + blockHash?: string; + /** @description Transaction nonce */ + nonce?: number; + /** @description Position of transaction within a block */ + transactionIndex?: number; + /** @description From address of transaction (hex string). */ + fromAddress?: string; + /** @description To address of transaction (hex string). null if contract creation. */ + toAddress?: string; + /** @description 20 Bytes - The contract address created, if the transaction was a contract creation, otherwise null */ + contractAddress?: string; + /** @description (uint8) Value of native token value moved within the external transaction */ + value?: string; + /** @description The total amount of gas used when this transaction was executed in the block. */ + cumulativeGasUsed?: string; + /** @description Gas price parameter */ + effectiveGasPrice?: string; + /** @description The amount of gas used by this specific transaction alone */ + gasUsed?: string; + /** @description Array of log objects, which this transaction generated */ + logs?: { + /** @description 20 Bytes - contract address from which this log originated. */ + contractAddress?: string; + /** @description Integer of the log index position in the block. null when its pending log. */ + logIndex?: string; + /** @description Contains one or more 32 Bytes non-indexed arguments of the log. */ + data?: string; + /** @description true when the log was removed, due to a chain reorganization. false if its a valid log. */ + removed?: boolean; + /** @description Array of zero to four 32 Bytes DATA of indexed log arguments */ + topics?: string[]; + }[]; + /** @description Array of internal transaction objects, which this transaction generated */ + internalTxns?: { + /** @description CALL or CREATE */ + type?: string; + /** @description 20 Bytes - address of the sender */ + fromAddress?: string; + /** @description 20 Bytes - address of the receiver. null when its a contract creation transaction */ + toAddress?: string; + /** @description amount of value for transfer (in hex) */ + value?: string; + /** @description amount of gas provided for the call (in hex) */ + gas?: string; + /** @description amount of gas used during the call (in hex) */ + gasUsed?: string; + /** @description call data */ + input?: string; + /** @description return data */ + output?: string; + /** @description error, if any */ + error?: string; + /** @description solidity revert reason, if any */ + revertReason?: string; + }[]; + }[]; + }; + TransactionHistoryResponseItem: { + /** @description Network associated with an individual transaction */ + network?: string; + /** @description Transaction hash */ + hash?: string; + /** @description (ISO 8601) Timestamp of transaction mining / confirmation */ + timeStamp?: string; + /** @description Block number of transaction mining / confirmation */ + blockNumber?: number; + /** @description Block hash of transaction mining / confirmation */ + blockHash?: string; + /** @description Transaction nonce */ + nonce?: number; + /** @description Position of transaction within a block */ + transactionIndex?: number; + /** @description From address of transaction (hex string). */ + fromAddress?: string; + /** @description To address of transaction (hex string). null if contract creation. */ + toAddress?: string; + /** @description 20 Bytes - The contract address created, if the transaction was a contract creation, otherwise null */ + contractAddress?: string; + /** @description (uint8) Value of native token value moved within the external transaction */ + value?: string; + /** @description The total amount of gas used when this transaction was executed in the block. */ + cumulativeGasUsed?: string; + /** @description Gas price parameter */ + effectiveGasPrice?: string; + /** @description The amount of gas used by this specific transaction alone */ + gasUsed?: string; + /** @description Array of log objects, which this transaction generated */ + logs?: { + /** @description 20 Bytes - contract address from which this log originated. */ + contractAddress?: string; + /** @description Integer of the log index position in the block. null when its pending log. */ + logIndex?: string; + /** @description Contains one or more 32 Bytes non-indexed arguments of the log. */ + data?: string; + /** @description true when the log was removed, due to a chain reorganization. false if its a valid log. */ + removed?: boolean; + /** @description Array of zero to four 32 Bytes DATA of indexed log arguments */ + topics?: string[]; + }[]; + /** @description Array of internal transaction objects, which this transaction generated */ + internalTxns?: { + /** @description CALL or CREATE */ + type?: string; + /** @description 20 Bytes - address of the sender */ + fromAddress?: string; + /** @description 20 Bytes - address of the receiver. null when its a contract creation transaction */ + toAddress?: string; + /** @description amount of value for transfer (in hex) */ + value?: string; + /** @description amount of gas provided for the call (in hex) */ + gas?: string; + /** @description amount of gas used during the call (in hex) */ + gasUsed?: string; + /** @description call data */ + input?: string; + /** @description return data */ + output?: string; + /** @description error, if any */ + error?: string; + /** @description solidity revert reason, if any */ + revertReason?: string; + }[]; + }; + TokenPricesResponse: { + /** @description List of token price data. */ + data: { + /** @description Token symbol. */ + symbol: string; + /** @description List of price information. */ + prices: { + /** @description Currency code (e.g., USD). */ + currency: string; + /** @description Price value as a string. */ + value: string; + /** + * Format: date-time + * @description Time when the price was last updated. + */ + lastUpdatedAt: string; + }[]; + /** @description Error message if applicable. */ + error: string | null; + }[]; + }; + TokenPriceResponseItem: { + /** @description Token symbol. */ + symbol: string; + /** @description List of price information. */ + prices: { + /** @description Currency code (e.g., USD). */ + currency: string; + /** @description Price value as a string. */ + value: string; + /** + * Format: date-time + * @description Time when the price was last updated. + */ + lastUpdatedAt: string; + }[]; + /** @description Error message if applicable. */ + error: string | null; + }; + BlockTimestampResponse: { + /** @description List of blocks */ + data: { + /** @description Network identifier */ + network: string; + block: { + /** @description Block number */ + number: number; + /** @description ISO timestamp of the block */ + timestamp: string; + }; + }[]; + }; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export interface operations { + "get-tokens-by-address": { + parameters: { + query?: never; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody: { + content: { + /** + * @example { + * "addresses": [ + * { + * "address": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152", + * "networks": [ + * "eth-mainnet", + * "base-mainnet", + * "matic-mainnet" + * ] + * } + * ], + * "withMetadata": true, + * "withPrices": true, + * "includeNativeTokens": true, + * "includeErc20Tokens": false + * } + */ + "application/json": { + /** @description Array of wallet addresses and the networks to query them on. Maximum 2 addresses and maximum 5 networks per address. */ + addresses: { + /** + * @description Wallet address. + * @default 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + * @example 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + */ + address: string; + /** + * @description Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains) + * @default [ + * "eth-mainnet", + * "base-mainnet", + * "matic-mainnet" + * ] + */ + networks: string[]; + }[]; + /** + * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @default true + */ + withMetadata?: boolean; + /** + * @description Boolean - if set to `true`, returns token prices. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @default true + */ + withPrices?: boolean; + /** + * @description Whether to include each chain's native token in the response (e.g. ETH on Ethereum). The native token will have a null contract address. + * @default true + * @example true + */ + includeNativeTokens?: boolean; + /** + * @description Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @default true + */ + includeErc20Tokens?: boolean; + }; + }; + }; + responses: { + /** @description Successful response! */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description List of tokens by address, with prices and metadata. */ + data: { + tokens?: { + /** @description Wallet address. */ + address: string; + /** @description Network identifier. */ + network: string; + /** @description Token address. */ + tokenAddress: string; + /** @description Balance of that particular token. */ + tokenBalance: string; + tokenMetadata?: { + /** @description Number of decimals the token uses */ + decimals?: number; + /** @description URL of the token's logo image */ + logo?: string; + /** @description Token's name */ + name?: string; + /** @description Token's symbol */ + symbol?: string; + }; + /** @description List of price information. */ + tokenPrices?: { + /** @example usd */ + currency: string; + /** @example 4608.2208671202 */ + value: string; + /** + * Format: date-time + * @example 2025-08-26T20:17:27Z + */ + lastUpdatedAt: string; + }[]; + /** @description Error message if applicable. */ + error?: string | null; + }[]; + pageKey?: string; + }; + }; + }; + }; + /** @description Bad Request: Invalid input (e.g., malformed JSON). */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error details. */ + error: { + /** @description Detailed error message. */ + message: string; + }; + }; + }; + }; + /** @description Too Many Requests: Rate limit exceeded. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error details. */ + error: { + /** @description Detailed error message. */ + message: string; + }; + }; + }; + }; + }; + }; + "get-token-balances-by-address": { + parameters: { + query?: never; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody: { + content: { + /** + * @example { + * "addresses": [ + * { + * "address": "0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152", + * "networks": [ + * "eth-mainnet", + * "base-mainnet", + * "matic-mainnet" + * ] + * } + * ], + * "includeNativeTokens": true, + * "includeErc20Tokens": false + * } + */ + "application/json": { + /** @description Array of address and networks pairs (limit 3 pairs, max 20 networks). Networks should match network enums. */ + addresses: { + /** + * @description Wallet address. + * @default 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + * @example 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + */ + address: string; + /** + * @description Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains) + * @default [ + * "eth-mainnet", + * "base-mainnet", + * "matic-mainnet" + * ] + */ + networks: string[]; + }[]; + /** + * @description Whether to include each chain's native token in the response (e.g. ETH on Ethereum). The native token will have a null contract address. + * @default true + * @example true + */ + includeNativeTokens?: boolean; + /** + * @description Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @default true + */ + includeErc20Tokens?: boolean; + }; + }; + }; + responses: { + /** @description Successful response! */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + data: { + /** @description List of token balances by address. */ + tokens?: { + /** @description Network identifier. */ + network: string; + /** @description Wallet address. */ + address: string; + /** @description Token address. */ + tokenAddress: string; + /** @description Balance of that particular token. */ + tokenBalance: string; + }[]; + pageKey?: string; + }; + }; + }; + }; + /** @description Bad Request: Invalid input (e.g., malformed JSON). */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error details. */ + error: { + /** @description Detailed error message. */ + message: string; + }; + }; + }; + }; + /** @description Too Many Requests: Rate limit exceeded. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error details. */ + error: { + /** @description Detailed error message. */ + message: string; + }; + }; + }; + }; + }; + }; + "get-nfts-by-address": { + parameters: { + query?: never; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @description Array of address and networks pairs (limit 2 pairs, max 15 networks each). Networks should match network enums. */ + addresses: { + /** + * @description Wallet address. + * @default 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + * @example 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + */ + address: string; + /** + * @description Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains) + * @default [ + * "eth-mainnet", + * "base-mainnet", + * "matic-mainnet" + * ] + */ + networks: ( + | "eth-mainnet" + | "eth-sepolia" + | "eth-holesky" + | "avax-mainnet" + | "avax-fuji" + | "zksync-mainnet" + | "opt-mainnet" + | "polygon-mainnet" + | "polygon-amoy" + | "arb-mainnet" + | "arb-sepolia" + | "blast-mainnet" + | "blast-sepolia" + | "base-mainnet" + | "base-sepolia" + | "soneium-mainnet" + | "soneium-minato" + | "scroll-mainnet" + | "scroll-sepolia" + | "shape-mainnet" + | "shape-sepolia" + | "lens-mainnet" + | "lens-sepolia" + | "starknet-mainnet" + | "starknet-sepolia" + | "rootstock-mainnet" + | "rootstock-testnet" + | "linea-mainnet" + | "linea-sepolia" + | "settlus-septestnet" + | "abstract-mainnet" + | "abstract-testnet" + | "apechain-mainnet" + )[]; + excludeFilters?: ("SPAM" | "AIRDROPS")[]; + includeFilters?: ("SPAM" | "AIRDROPS")[]; + /** @enum {string} */ + spamConfidenceLevel?: "VERY_HIGH" | "HIGH" | "MEDIUM" | "LOW"; + }[]; + /** + * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @default true + */ + withMetadata?: boolean; + pageKey?: string; + /** @default 100 */ + pageSize?: number; + } & { + /** + * @description Field to order results by + * @enum {string} + */ + orderBy?: "transferTime"; + /** + * @description Sort order for results + * @enum {string} + */ + sortOrder?: "asc" | "desc"; + }; + }; + }; + responses: { + /** @description Successful response! */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description List of nfts by address with appropriate metadata. */ + data: { + ownedNfts?: { + /** @description Network identifier. */ + network?: string; + /** @description Wallet address. */ + address?: string; + /** @description The contract object that has details of a contract */ + contract?: { + /** @description Address of the held contract */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description List of reasons why a contract was classified as spam. **Only available on paid tiers.** */ + spamClassifications?: string[]; + }; + /** @default 44 */ + tokenId: string; + tokenType?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Brief human-readable description */ + description?: string; + /** @description Details of the image corresponding to this contract */ + image?: { + /** @description The Url of the image stored in Alchemy cache */ + cachedUrl?: string; + /** @description The Url that has the thumbnail version of the NFT */ + thumbnailUrl?: string; + /** @description The Url that has the NFT image in png */ + pngUrl?: string; + /** @description The Url of the image stored in Alchemy cache */ + contentType?: string; + /** @description The size of the media asset in bytes. */ + size?: number; + /** @description The original Url of the image coming straight from the smart contract */ + originalUrl?: string; + }; + /** @description Raw details of the NFT like its tokenUri and metadata info obtained directly from the smart contract */ + raw?: { + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description Relevant metadata for NFT contract. This is useful for viewing image url, traits, etc. without having to follow the metadata url in tokenUri to parse manually. */ + metadata?: { + /** @description String - URL to the NFT asset image. Can be standard URLs pointing to images on conventional servers, IPFS, or Arweave. Most types of images (SVGs, PNGs, JPEGs, etc.) are supported by NFT marketplaces. */ + image?: string; + /** @description String - Name of the NFT asset. */ + name?: string; + /** @description String - Human-readable description of the NFT asset. (Markdown is supported/rendered on OpenSea and other NFT platforms) */ + description?: string; + /** @description Object - Traits/attributes/characteristics for each NFT asset. */ + attributes?: { + value?: string; + trait_type?: string; + }[]; + }; + /** @description String - A string describing a particular reason that we were unable to fetch complete metadata for the NFT. */ + error?: string; + }; + /** @description The collection object that has details of a collection */ + collection?: { + /** @description String - Collection name */ + name?: string; + /** @description String - OpenSea collection slug */ + slug?: string; + /** @description String - URL for the external site of the collection */ + externalUrl?: string; + /** @description String - Banner image URL for the collection */ + bannerImageUrl?: string; + }; + /** @description String - Uri representing the location of the NFT's original metadata blob. This is a backup for you to parse when the metadata field is not automatically populated. */ + tokenUri?: string; + /** @description String - ISO timestamp of the last cache refresh for the information returned in the metadata field. */ + timeLastUpdated?: string; + /** @description Only present if the request specified `orderBy=transferTime`. */ + acquiredAt?: { + /** @description Block timestamp of the block where the NFT was most recently acquired. */ + blockTimestamp?: string; + /** @description Block number of the block where the NFT was most recently acquired. */ + blockNumber?: string; + }; + }[]; + /** @description Integer - Total number of NFTs (distinct `tokenIds`) owned by the given address. */ + totalCount?: number; + pageKey?: string; + }; + }; + }; + }; + /** @description Bad Request: Invalid input (e.g., malformed JSON). */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error details. */ + error: { + /** @description Detailed error message. */ + message: string; + }; + }; + }; + }; + /** @description Too Many Requests: Rate limit exceeded. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error details. */ + error: { + /** @description Detailed error message. */ + message: string; + }; + }; + }; + }; + }; + }; + "get-nft-contracts-by-address": { + parameters: { + query?: never; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @description Array of address and networks pairs (limit 2 pairs, max 15 networks each). Networks should match network enums. */ + addresses: { + /** + * @description Wallet address. + * @default 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + * @example 0x1E6E8695FAb3Eb382534915eA8d7Cc1D1994B152 + */ + address: string; + /** + * @description Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains) + * @default [ + * "eth-mainnet", + * "base-mainnet", + * "matic-mainnet" + * ] + */ + networks: ( + | "eth-mainnet" + | "eth-sepolia" + | "eth-holesky" + | "avax-mainnet" + | "avax-fuji" + | "zksync-mainnet" + | "opt-mainnet" + | "polygon-mainnet" + | "polygon-amoy" + | "arb-mainnet" + | "arb-sepolia" + | "blast-mainnet" + | "blast-sepolia" + | "base-mainnet" + | "base-sepolia" + | "soneium-mainnet" + | "soneium-minato" + | "scroll-mainnet" + | "scroll-sepolia" + | "shape-mainnet" + | "shape-sepolia" + | "lens-mainnet" + | "lens-sepolia" + | "starknet-mainnet" + | "starknet-sepolia" + | "rootstock-mainnet" + | "rootstock-testnet" + | "linea-mainnet" + | "linea-sepolia" + | "settlus-septestnet" + | "abstract-mainnet" + | "abstract-testnet" + | "apechain-mainnet" + )[]; + excludeFilters?: ("SPAM" | "AIRDROPS")[]; + includeFilters?: ("SPAM" | "AIRDROPS")[]; + /** @enum {string} */ + spamConfidenceLevel?: "VERY_HIGH" | "HIGH" | "MEDIUM" | "LOW"; + }[]; + /** + * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @default true + */ + withMetadata?: boolean; + pageKey?: string; + /** @default 100 */ + pageSize?: number; + } & { + /** + * @description Field to order results by + * @enum {string} + */ + orderBy?: "transferTime"; + /** + * @description Sort order for results + * @enum {string} + */ + sortOrder?: "asc" | "desc"; + }; + }; + }; + responses: { + /** @description Successful response! */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description List of nft collections. */ + data: { + contracts?: { + /** @description Network identifier. */ + network?: string; + /** @description Wallet address. */ + address?: string; + /** @description The contract object that has details of a contract */ + contract?: { + /** @description Address of the held contract */ + address?: string; + /** @description String - NFT contract name. */ + name?: string; + /** @description String - NFT contract symbol abbreviation. */ + symbol?: string; + /** @description String - Total number of NFTs in a given NFT collection. */ + totalSupply?: string; + /** + * @description String - For valid NFTs, 'ERC721' or 'ERC1155.' For invalid NFTs, a descriptive reason such as 'NO_SUPPORTED_NFT_STANDARD' if the input contract address doesn't support a known NFT standard, or 'NOT_A_CONTRACT' if there is no contract deployed at the input address. + * @enum {string} + */ + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + /** @description String - Address that deployed the smart contract */ + contractDeployer?: string; + /** @description Number - The Block Number when the deployment transaction is successfully mined */ + deployedBlockNumber?: number; + /** @description Note that the OpenSea metadata object is currently only available on ETH and Polygon Mainnet. Please reach out to us at support@alchemy.com if you would like to access this data on other networks. */ + openseaMetadata?: { + /** @description NFT floor price */ + floorPrice?: number; + /** @description OpenSea collection name */ + collectionName?: string; + /** @description Collection approval status within OpenSea. For more info, see the Opensea docs at docs.opensea.io/reference/collection-model */ + safelistRequestStatus?: string; + /** @description OpenSea CDN image URL */ + imageUrl?: string; + /** @description OpenSea collection description. Note: this value is truncated to 255 characters. */ + description?: string; + /** @description Collection homepage */ + externalUrl?: string; + /** @description The twitter username of the collection */ + twitterUsername?: string; + /** @description The discord URL of the collection */ + discordUrl?: string; + /** @description The banner image URL of the collection */ + bannerImageUrl?: string; + /** @description The timestamp when the collection was last ingested by us */ + lastIngestedAt?: string; + }; + /** @description "true" if contract is spam, else "false". **Only available on paid tiers.** */ + isSpam?: string; + /** @description List of reasons why a contract was classified as spam. **Only available on paid tiers.** */ + spamClassifications?: string[]; + }; + }[]; + /** @description Integer - Total number of NFTs (distinct `tokenIds`) owned by the given address. */ + totalCount?: number; + pageKey?: string; + }; + }; + }; + }; + /** @description Bad Request: Invalid input (e.g., malformed JSON). */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error details. */ + error: { + /** @description Detailed error message. */ + message: string; + }; + }; + }; + }; + /** @description Too Many Requests: Rate limit exceeded. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error details. */ + error: { + /** @description Detailed error message. */ + message: string; + }; + }; + }; + }; + }; + }; +} diff --git a/packages/data-apis/src/generated/rpc/transfers.ts b/packages/data-apis/src/generated/rpc/transfers.ts new file mode 100644 index 0000000000..9cb54064dc --- /dev/null +++ b/packages/data-apis/src/generated/rpc/transfers.ts @@ -0,0 +1,125 @@ +/* eslint-disable -- machine-generated file */ +// AUTO-GENERATED by @alchemy/api-codegen — DO NOT EDIT. +// Regenerate with `pnpm generate`. Spec provenance (docs repo commit + checksums) +// is recorded in packages/api-codegen/specs/specs.lock.json. + +export interface AlchemyGetAssetTransfersParams { + fromBlock?: string; + toBlock?: string; + fromAddress?: string; + toAddress?: string; + excludeZeroValue?: boolean; + /** + * Array of transfer categories to include. Note: 'internal' category is not supported on Base, it is only available on Ethereum Mainnet and Polygon Mainnet. + */ + category?: ( + | "external" + | "internal" + | "erc20" + | "erc721" + | "erc1155" + | "specialnft" + )[]; + /** + * An array of contract addresses to filter for. + */ + contractAddresses?: string[]; + order?: "asc" | "desc"; + /** + * Available only on ETH, Base, Polygon, Arbitrum, Optimism + */ + withMetadata?: boolean; + maxCount?: string; + pageKey?: string; +} + +export type AlchemyGetAssetTransfersResult = + | NotFoundNull + | { + /** + * Uuid of next page of results (if exists, else blank). + */ + pageKey?: string; + /** + * Array of transfer objects sorted in ascending or descending order by block number. + */ + transfers?: { + /** + * 'external', 'internal', 'token', 'erc20', 'erc721', 'erc1155', 'specialnft' + */ + category?: string; + /** + * Block number of the transfer (hex string). + */ + blockNum?: string; + /** + * From address (hex string). + */ + from?: string; + /** + * To address (hex string). null if contract creation. + */ + to?: string; + /** + * Asset transfer value. null if it's an ERC721 or unknown decimals. + */ + value?: number; + /** + * (Deprecated) Legacy token ID field for ERC721 tokens. Use `tokenId` instead. + */ + erc721TokenId?: string; + /** + * Array of objects with (tokenId, value) for ERC1155 transfers, null otherwise. + */ + erc1155Metadata?: { + tokenId?: string; + value?: string; + }[]; + /** + * Token ID for NFT tokens (ERC721, ERC1155, etc.). + */ + tokenId?: string; + /** + * ETH or the token's symbol. null if unavailable. + */ + asset?: string; + /** + * Unique identifier for the transfer object. + */ + uniqueId?: string; + /** + * Transaction hash (hex string). + */ + hash?: string; + rawContract?: { + /** + * Raw hex transfer value. null for NFT transfers. + */ + value?: string; + /** + * Contract address (hex string). null for external or internal transfers. + */ + address?: string; + /** + * Contract decimal in hex. null if not known. + */ + decimal?: string; + }; + metadata?: { + /** + * ISO-formatted timestamp of the block containing this transfer. (Available only on ETH, Base, Polygon, Arbitrum, Optimism) + */ + blockTimestamp?: string; + }; + }[]; + }; +export type NotFoundNull = string; + +/** viem RpcSchema entries for the transfers JSON-RPC methods. */ +export type TransfersRpcSchema = [ + { + Method: "alchemy_getAssetTransfers"; + Parameters: [assetTransferParams: AlchemyGetAssetTransfersParams]; + ReturnType: AlchemyGetAssetTransfersResult; + }, +]; diff --git a/packages/data-apis/src/index.ts b/packages/data-apis/src/index.ts new file mode 100644 index 0000000000..395254ca25 --- /dev/null +++ b/packages/data-apis/src/index.ts @@ -0,0 +1,21 @@ +// client +export type { AlchemyDataClient, AlchemyDataClientOptions } from "./client.js"; +export { createDataClient } from "./client.js"; + +// decorator +export type { DataActions } from "./decorator.js"; +export { dataActions } from "./decorator.js"; + +// actions (individually importable for tree-shaking / composability) +export { getTokensByAddress } from "./actions/portfolio/getTokensByAddress.js"; +export { getNftsForOwner } from "./actions/nft/getNftsForOwner.js"; +export { getAssetTransfers } from "./actions/transfers/getAssetTransfers.js"; + +// schemas +export type { DataRpcSchema } from "./schema/rpc.js"; +export type { PortfolioRestSchema, NftRestSchema } from "./schema/rest.js"; + +// types +export type * from "./types.js"; + +export { VERSION } from "./version.js"; diff --git a/packages/data-apis/src/internal/clientHelpers.ts b/packages/data-apis/src/internal/clientHelpers.ts new file mode 100644 index 0000000000..8f5fa05ec2 --- /dev/null +++ b/packages/data-apis/src/internal/clientHelpers.ts @@ -0,0 +1,74 @@ +import { + AlchemyRestClient, + resolveNetwork, + type AlchemyTransport, + type AlchemyTransportConfig, + type NetworkInput, + type ResolvedNetwork, + type RestRequestSchema, +} from "@alchemy/common"; +import { BaseError } from "@alchemy/common"; +import type { Chain, Client } from "viem"; + +/** The minimal client shape data actions operate on. */ +export type DataClient = Client; + +/** + * Reads the AlchemyTransportConfig back off an instantiated client transport. + * The transport attaches its creation config to the transport value precisely + * to support deriving new instances (tracing relies on the same mechanism). + * + * @param {DataClient} client The client to read from + * @returns {AlchemyTransportConfig} The transport's creation config + */ +export function getTransportConfig(client: DataClient): AlchemyTransportConfig { + return client.transport.config as AlchemyTransportConfig; +} + +/** + * Resolves the network for a request: explicit per-request input wins, + * otherwise the client's chain (set at client creation). The + * `custom.alchemyNetwork` field carries slug-configured defaults (e.g. Solana + * or escape-hatch networks that have no registry chain ID). + * + * @param {DataClient} client The client whose chain provides the default + * @param {NetworkInput} [override] Per-request network override + * @returns {ResolvedNetwork} The resolved network + */ +export function resolveRequestNetwork( + client: DataClient, + override?: NetworkInput, +): ResolvedNetwork { + if (override != null) { + return resolveNetwork(override); + } + const chain = client.chain; + const customSlug = (chain?.custom as { alchemyNetwork?: string } | undefined) + ?.alchemyNetwork; + if (customSlug) { + return resolveNetwork(customSlug); + } + if (chain) { + return resolveNetwork(chain); + } + throw new BaseError( + "No network available: pass `network` on the request or configure the client with a network/chain.", + ); +} + +/** + * Builds a typed REST client for a service base URL, reusing the auth + * (apiKey/JWT) and headers from the viem client's Alchemy transport so REST + * and JSON-RPC requests share one connection config. + * + * @param {DataClient} client The client whose transport supplies auth + * @param {string} url The service base URL + * @returns {AlchemyRestClient} A typed REST client + */ +export function getRestClient( + client: DataClient, + url: string, +): AlchemyRestClient { + const { apiKey, jwt } = getTransportConfig(client); + return new AlchemyRestClient({ apiKey, jwt, url }); +} diff --git a/packages/data-apis/src/internal/endpoints.ts b/packages/data-apis/src/internal/endpoints.ts new file mode 100644 index 0000000000..a870a9182f --- /dev/null +++ b/packages/data-apis/src/internal/endpoints.ts @@ -0,0 +1,23 @@ +// Per-service endpoint resolution. The slug comes from resolveNetwork in +// @alchemy/common, so all three network input formats land here identically. + +/** Global, chain-agnostic Data API (multi-network request bodies). */ +export const DATA_API_URL = "https://api.g.alchemy.com/data/v1"; + +/** + * Network-scoped NFT v3 base URL. + * + * @param {string} slug The Alchemy network slug + * @returns {string} The NFT v3 base URL for that network + */ +export const getNftApiUrl = (slug: string): string => + `https://${slug}.g.alchemy.com/nft/v3`; + +/** + * Network-scoped JSON-RPC base URL. + * + * @param {string} slug The Alchemy network slug + * @returns {string} The RPC base URL for that network + */ +export const getRpcUrl = (slug: string): string => + `https://${slug}.g.alchemy.com/v2`; diff --git a/packages/data-apis/src/schema/rest.ts b/packages/data-apis/src/schema/rest.ts new file mode 100644 index 0000000000..a725eb72c5 --- /dev/null +++ b/packages/data-apis/src/schema/rest.ts @@ -0,0 +1,5 @@ +// Generated by @alchemy/api-codegen from the docs repo's bundled OpenAPI +// specs (see src/generated/). Re-exported here so the public import path is +// stable regardless of how generation is organized internally. +export type { NftRestSchema } from "../generated/rest/nft.schema.js"; +export type { PortfolioRestSchema } from "../generated/rest/portfolio.schema.js"; diff --git a/packages/data-apis/src/schema/rpc.ts b/packages/data-apis/src/schema/rpc.ts new file mode 100644 index 0000000000..fb3b5fec9d --- /dev/null +++ b/packages/data-apis/src/schema/rpc.ts @@ -0,0 +1,22 @@ +import type { AlchemyGetAssetTransfersParams } from "../generated/rpc/transfers.js"; +import type { GetAssetTransfersResult } from "../types.js"; + +// Params/result internals are generated by @alchemy/api-codegen from the docs +// repo's bundled OpenRPC specs (see src/generated/rpc/). + +export type GetAssetTransfersRpcParams = AlchemyGetAssetTransfersParams; + +/** + * viem RpcSchema entries for the Data JSON-RPC methods. Attach to a client to + * get typed `client.request({ method: "alchemy_getAssetTransfers", ... })`. + * + * ReturnType uses the SDK's {@link GetAssetTransfersResult}, which collapses + * the spec's "Not Found (null)" string branch (a docs-spec artifact). + */ +export type DataRpcSchema = [ + { + Method: "alchemy_getAssetTransfers"; + Parameters: [AlchemyGetAssetTransfersParams]; + ReturnType: GetAssetTransfersResult; + }, +]; diff --git a/packages/data-apis/src/types.ts b/packages/data-apis/src/types.ts new file mode 100644 index 0000000000..6c848d7b1d --- /dev/null +++ b/packages/data-apis/src/types.ts @@ -0,0 +1,80 @@ +import type { NetworkInput } from "@alchemy/common"; +import type { + GetNftsForOwnerQuery, + GetNftsForOwnerResponse, +} from "./generated/rest/nft.schema.js"; +import type { + GetTokensByAddressBody, + GetTokensByAddressResponse, +} from "./generated/rest/portfolio.schema.js"; +import type { + AlchemyGetAssetTransfersParams, + AlchemyGetAssetTransfersResult, +} from "./generated/rpc/transfers.js"; + +// Public param/result types are hand-reviewed aliases over generated +// internals (src/generated/, produced by @alchemy/api-codegen from the docs +// repo's bundled OpenAPI/OpenRPC specs). Generated names are never +// re-exported directly: every public-surface change is a deliberate edit +// here, even when the underlying spec moves. + +/** An address paired with the networks to query it on. */ +export interface PortfolioAddressEntry { + address: string; + /** Networks to query; accepts viem Chains, Alchemy slugs, or CAIP-2 ids. */ + networks: NetworkInput[]; +} + +/** + * Generated request body with the wire-format `addresses` (plain string + * networks) replaced by the SDK's three-format {@link PortfolioAddressEntry}. + */ +export type GetTokensByAddressParams = Omit< + GetTokensByAddressBody, + "addresses" +> & { + addresses: PortfolioAddressEntry[]; +}; + +export type GetTokensByAddressResult = GetTokensByAddressResponse; + +export type PortfolioToken = NonNullable< + GetTokensByAddressResponse["data"]["tokens"] +>[number]; + +/** + * Generated query params plus the SDK's network override; the wire's + * bracketed `contractAddresses[]` key is replaced with a plain array (the + * action serializes it back to the bracketed form). + */ +export type GetNftsForOwnerParams = Omit< + GetNftsForOwnerQuery, + "contractAddresses[]" +> & { + /** Overrides the client-level network for this request. */ + network?: NetworkInput; + /** Contract addresses to filter by (max 45). */ + contractAddresses?: string[]; +}; + +export type GetNftsForOwnerResult = GetNftsForOwnerResponse; + +/** Generated RPC params plus the SDK's network override. */ +export type GetAssetTransfersParams = AlchemyGetAssetTransfersParams & { + /** Overrides the client-level network for this request. */ + network?: NetworkInput; +}; + +/** + * The spec result is `oneOf: ["Not Found (null)" string, object]`; the string + * branch is a docs-spec artifact the SDK deliberately does not surface, so it + * is collapsed away here (and in {@link DataRpcSchema}). + */ +export type GetAssetTransfersResult = Exclude< + AlchemyGetAssetTransfersResult, + string +>; + +export type AssetTransfer = NonNullable< + GetAssetTransfersResult["transfers"] +>[number]; diff --git a/packages/data-apis/src/version.ts b/packages/data-apis/src/version.ts new file mode 100644 index 0000000000..128c5e1f2d --- /dev/null +++ b/packages/data-apis/src/version.ts @@ -0,0 +1,3 @@ +// This file is autogenerated by inject-version.ts. Any changes will be +// overwritten on commit! +export const VERSION = "0.0.0"; diff --git a/packages/data-apis/tsconfig.build.json b/packages/data-apis/tsconfig.build.json new file mode 100644 index 0000000000..a9532f066c --- /dev/null +++ b/packages/data-apis/tsconfig.build.json @@ -0,0 +1,17 @@ +{ + "extends": "typescript-template/build.json", + "exclude": [ + "node_modules", + "**/*/__tests__", + "**/*/*.test.ts", + "**/*/*.test-d.ts", + "**/*/*.e2e.test.ts", + "vitest.config.ts", + "vitest.config.e2e.ts" + ], + "include": ["src"], + "compilerOptions": { + "sourceMap": true, + "jsx": "react-jsx" + } +} diff --git a/packages/data-apis/tsconfig.json b/packages/data-apis/tsconfig.json new file mode 100644 index 0000000000..ad56d6c756 --- /dev/null +++ b/packages/data-apis/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "typescript-template/base.json", + "compilerOptions": { + "jsx": "preserve", + "paths": { + "~test/*": ["../../.vitest/src/*"] + } + } +} diff --git a/packages/data-apis/vitest.config.ts b/packages/data-apis/vitest.config.ts new file mode 100644 index 0000000000..160b2a76d1 --- /dev/null +++ b/packages/data-apis/vitest.config.ts @@ -0,0 +1,14 @@ +import { defineProject } from "vitest/config"; + +export default defineProject({ + test: { + name: "alchemy/data-apis", + globals: true, + include: ["src/**/*.test.ts"], + // Unit tests stub fetch; no anvil/bundler setup needed (same as common) + setupFiles: [], + globalSetup: undefined, + testTimeout: 10_000, + hookTimeout: 10_000, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 077abdcdf6..0ca8616a60 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -220,6 +220,21 @@ importers: specifier: ^2.45.0 version: 2.46.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.4.3) + packages/api-codegen: + devDependencies: + json-schema-to-typescript: + specifier: 15.0.4 + version: 15.0.4 + openapi-typescript: + specifier: 7.13.0 + version: 7.13.0(typescript@5.9.3) + prettier: + specifier: 3.3.3 + version: 3.3.3 + typescript-template: + specifier: workspace:* + version: link:../../templates/typescript + packages/common: dependencies: zod: @@ -236,6 +251,22 @@ importers: specifier: ^2.45.0 version: 2.46.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76) + packages/data-apis: + dependencies: + '@alchemy/common': + specifier: workspace:* + version: link:../common + devDependencies: + '@alchemy/api-codegen': + specifier: workspace:* + version: link:../api-codegen + typescript-template: + specifier: workspace:* + version: link:../../templates/typescript + viem: + specifier: ^2.45.0 + version: 2.46.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.4.3) + packages/smart-accounts: dependencies: '@alchemy/common': @@ -340,6 +371,10 @@ packages: peerDependencies: typescript: ^5.8.2 + '@apidevtools/json-schema-ref-parser@11.9.3': + resolution: {integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==} + engines: {node: '>= 16'} + '@asamuzakjp/css-color@3.2.0': resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} @@ -1508,6 +1543,9 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@jsdevtools/ono@7.1.3': + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + '@lerna/create@8.2.4': resolution: {integrity: sha512-A8AlzetnS2WIuhijdAzKUyFpR5YbLLfV3luQ4lzBgIBgRfuoBDZeF+RSZPhra+7A6/zTUlrbhKZIOi/MNhqgvQ==} engines: {node: '>=18.0.0'} @@ -1616,17 +1654,6 @@ packages: resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} engines: {node: ^14.21.3 || >=16} - '@noble/curves@1.4.2': - resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} - - '@noble/curves@1.8.0': - resolution: {integrity: sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ==} - engines: {node: ^14.21.3 || >=16} - - '@noble/curves@1.8.1': - resolution: {integrity: sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==} - engines: {node: ^14.21.3 || >=16} - '@noble/curves@1.9.1': resolution: {integrity: sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==} engines: {node: ^14.21.3 || >=16} @@ -1635,18 +1662,6 @@ packages: resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} engines: {node: ^14.21.3 || >=16} - '@noble/hashes@1.4.0': - resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} - engines: {node: '>= 16'} - - '@noble/hashes@1.7.0': - resolution: {integrity: sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==} - engines: {node: ^14.21.3 || >=16} - - '@noble/hashes@1.7.1': - resolution: {integrity: sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==} - engines: {node: ^14.21.3 || >=16} - '@noble/hashes@1.8.0': resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} @@ -1911,6 +1926,16 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@redocly/ajv@8.11.2': + resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==} + + '@redocly/config@0.22.0': + resolution: {integrity: sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ==} + + '@redocly/openapi-core@1.34.15': + resolution: {integrity: sha512-HAwCnNyKcs5XGQqms+9t7OdAPM/5TDstmhF+0i7tdCFato2QKuYIlyWETwkXd8c5zbltr1oB+6y9NTeQLr2d6Q==} + engines: {node: '>=18.17.0', npm: '>=9.5.0'} + '@reown/appkit-common@1.7.8': resolution: {integrity: sha512-ridIhc/x6JOp7KbDdwGKY4zwf8/iK8EYBl+HtWrruutSLwZyVi5P8WaZa+8iajL6LcDcDF7LoyLwMTym7SRuwQ==} @@ -3480,6 +3505,9 @@ packages: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} hasBin: true + colorette@1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -4788,6 +4816,10 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} + index-to-position@1.2.0: + resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==} + engines: {node: '>=18'} + inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. @@ -5114,6 +5146,10 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + js-levenshtein@1.1.6: + resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} + engines: {node: '>=0.10.0'} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -5171,6 +5207,11 @@ packages: json-rpc-random-id@1.0.1: resolution: {integrity: sha512-RJ9YYNCkhVDBuP4zN5BBtYAzEl03yq/jIIsyif0JY9qyJuQQZNeDK7anAPKKlyEtLSj2s8h6hNh2F8zO5q7ScA==} + json-schema-to-typescript@15.0.4: + resolution: {integrity: sha512-Su9oK8DR4xCmDsLlyvadkXzX6+GGXJpbhwoLtOGArAG61dvbW4YQmSEno2y66ahpIdmLMg6YUf/QHLgiwvkrHQ==} + engines: {node: '>=16.0.0'} + hasBin: true + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -6145,6 +6186,12 @@ packages: zod: optional: true + openapi-typescript@7.13.0: + resolution: {integrity: sha512-EFP392gcqXS7ntPvbhBzbF8TyBA+baIYEm791Hy5YkjDYKTnk/Tn5OQeKm5BIZvJihpp8Zzr4hzx0Irde1LNGQ==} + hasBin: true + peerDependencies: + typescript: ^5.x + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -6292,6 +6339,10 @@ packages: resolution: {integrity: sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==} engines: {node: '>=16'} + parse-json@8.3.0: + resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} + engines: {node: '>=18'} + parse-ms@4.0.0: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} @@ -6407,6 +6458,10 @@ packages: resolution: {integrity: sha512-t1Ax8KUvV3FFII8ltczPn2tJdjqbd1sIzu6t4JL7nQ3EyeL/lTrj5PWKb06ic5/6XYDr65rQ4uzQEGN70/6X5w==} engines: {node: '>=6'} + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + pngjs@5.0.0: resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} engines: {node: '>=10.13.0'} @@ -7108,6 +7163,10 @@ packages: resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} engines: {node: '>=14.0.0'} + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -7361,6 +7420,10 @@ packages: resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} engines: {node: '>=14.16'} + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -7602,6 +7665,9 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + uri-js-replace@1.0.1: + resolution: {integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -7996,6 +8062,9 @@ packages: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} + yaml-ast-parser@0.0.43: + resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==} + yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} @@ -8118,6 +8187,12 @@ snapshots: - bufferutil - utf-8-validate + '@apidevtools/json-schema-ref-parser@11.9.3': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + js-yaml: 4.1.1 + '@asamuzakjp/css-color@3.2.0': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) @@ -8147,7 +8222,7 @@ snapshots: '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -8207,7 +8282,7 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-compilation-targets': 7.28.6 '@babel/helper-plugin-utils': 7.28.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) lodash.debounce: 4.0.8 resolve: 1.22.11 transitivePeerDependencies: @@ -8956,7 +9031,7 @@ snapshots: '@babel/parser': 7.29.0 '@babel/template': 7.28.6 '@babel/types': 7.29.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -8967,7 +9042,7 @@ snapshots: '@base-org/account@1.1.1(bufferutil@4.1.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@4.4.3)': dependencies: - '@noble/hashes': 1.4.0 + '@noble/hashes': 1.8.0 clsx: 1.2.1 eventemitter3: 5.0.1 idb-keyval: 6.2.1 @@ -9001,7 +9076,7 @@ snapshots: '@coinbase/wallet-sdk@4.3.6(bufferutil@4.1.0)(react@18.3.1)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@4.4.3)': dependencies: - '@noble/hashes': 1.4.0 + '@noble/hashes': 1.8.0 clsx: 1.2.1 eventemitter3: 5.0.1 idb-keyval: 6.2.1 @@ -9278,7 +9353,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.14.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -9330,7 +9405,7 @@ snapshots: '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -9509,6 +9584,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@jsdevtools/ono@7.1.3': {} + '@lerna/create@8.2.4(@types/node@22.19.15)(babel-plugin-macros@3.1.0)(encoding@0.1.13)(typescript@5.9.3)': dependencies: '@npmcli/arborist': 7.5.4 @@ -9701,7 +9778,7 @@ snapshots: bufferutil: 4.1.0 cross-fetch: 4.1.0(encoding@0.1.13) date-fns: 2.30.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) eciesjs: 0.4.17 eventemitter2: 6.4.9 readable-stream: 3.6.2 @@ -9725,7 +9802,7 @@ snapshots: '@paulmillr/qr': 0.2.1 bowser: 2.14.1 cross-fetch: 4.1.0(encoding@0.1.13) - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) eciesjs: 0.4.17 eth-rpc-errors: 4.0.3 eventemitter2: 6.4.9 @@ -9752,7 +9829,7 @@ snapshots: '@scure/base': 1.2.6 '@types/debug': 4.1.12 '@types/lodash': 4.17.24 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) lodash: 4.17.23 pony-cause: 2.1.11 semver: 7.7.4 @@ -9764,7 +9841,7 @@ snapshots: dependencies: '@ethereumjs/tx': 4.2.0 '@types/debug': 4.1.12 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) semver: 7.7.4 superstruct: 1.0.4 transitivePeerDependencies: @@ -9777,7 +9854,7 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 '@types/debug': 4.1.12 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) pony-cause: 2.1.11 semver: 7.7.4 uuid: 9.0.1 @@ -9791,7 +9868,7 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 '@types/debug': 4.1.12 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) pony-cause: 2.1.11 semver: 7.7.4 uuid: 9.0.1 @@ -9812,18 +9889,6 @@ snapshots: '@noble/ciphers@1.3.0': {} - '@noble/curves@1.4.2': - dependencies: - '@noble/hashes': 1.4.0 - - '@noble/curves@1.8.0': - dependencies: - '@noble/hashes': 1.7.0 - - '@noble/curves@1.8.1': - dependencies: - '@noble/hashes': 1.7.1 - '@noble/curves@1.9.1': dependencies: '@noble/hashes': 1.8.0 @@ -9832,12 +9897,6 @@ snapshots: dependencies: '@noble/hashes': 1.8.0 - '@noble/hashes@1.4.0': {} - - '@noble/hashes@1.7.0': {} - - '@noble/hashes@1.7.1': {} - '@noble/hashes@1.8.0': {} '@nodelib/fs.scandir@2.1.5': @@ -9856,7 +9915,7 @@ snapshots: dependencies: agent-base: 7.1.4 http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 + https-proxy-agent: 7.0.6(supports-color@10.2.2) lru-cache: 10.4.3 socks-proxy-agent: 8.0.5 transitivePeerDependencies: @@ -10208,6 +10267,29 @@ snapshots: '@pkgr/core@0.2.9': {} + '@redocly/ajv@8.11.2': + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js-replace: 1.0.1 + + '@redocly/config@0.22.0': {} + + '@redocly/openapi-core@1.34.15(supports-color@10.2.2)': + dependencies: + '@redocly/ajv': 8.11.2 + '@redocly/config': 0.22.0 + colorette: 1.4.0 + https-proxy-agent: 7.0.6(supports-color@10.2.2) + js-levenshtein: 1.1.6 + js-yaml: 4.1.1 + minimatch: 5.1.9 + pluralize: 8.0.0 + yaml-ast-parser: 0.0.43 + transitivePeerDependencies: + - supports-color + '@reown/appkit-common@1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.22.4)': dependencies: big.js: 6.2.2 @@ -10576,8 +10658,8 @@ snapshots: '@scure/bip32@1.4.0': dependencies: - '@noble/curves': 1.4.2 - '@noble/hashes': 1.4.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 '@scure/base': 1.1.9 '@scure/bip32@1.7.0': @@ -10588,7 +10670,7 @@ snapshots: '@scure/bip39@1.3.0': dependencies: - '@noble/hashes': 1.4.0 + '@noble/hashes': 1.8.0 '@scure/base': 1.1.9 '@scure/bip39@1.6.0': @@ -11339,7 +11421,7 @@ snapshots: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1)(typescript@5.9.3) '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.9.3) - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) eslint: 8.57.1 graphemer: 1.4.0 ignore: 5.3.2 @@ -11364,7 +11446,7 @@ snapshots: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.9.3) - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) eslint: 8.57.1 optionalDependencies: typescript: 5.9.3 @@ -11380,7 +11462,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.9.3) '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.9.3) - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) eslint: 8.57.1 tsutils: 3.21.0(typescript@5.9.3) optionalDependencies: @@ -11396,7 +11478,7 @@ snapshots: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) globby: 11.1.0 is-glob: 4.0.3 semver: 7.7.4 @@ -11744,8 +11826,8 @@ snapshots: '@walletconnect/relay-auth@1.1.0': dependencies: - '@noble/curves': 1.8.0 - '@noble/hashes': 1.7.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 uint8arrays: 3.1.0 @@ -11971,8 +12053,8 @@ snapshots: '@walletconnect/utils@2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.4.3)': dependencies: '@noble/ciphers': 1.2.1 - '@noble/curves': 1.8.1 - '@noble/hashes': 1.7.1 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/relay-api': 1.0.11 @@ -12015,8 +12097,8 @@ snapshots: '@walletconnect/utils@2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.4.3)': dependencies: '@noble/ciphers': 1.2.1 - '@noble/curves': 1.8.1 - '@noble/hashes': 1.7.1 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/relay-api': 1.0.11 @@ -12636,6 +12718,8 @@ snapshots: color-support@1.1.3: {} + colorette@1.4.0: {} + colorette@2.0.20: {} columnify@1.6.0: @@ -12881,9 +12965,11 @@ snapshots: dependencies: ms: 2.1.2 - debug@4.4.3: + debug@4.4.3(supports-color@10.2.2): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 10.2.2 decamelize-keys@1.1.1: dependencies: @@ -13066,7 +13152,7 @@ snapshots: engine.io-client@6.6.4(bufferutil@4.1.0)(utf-8-validate@5.0.10): dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) engine.io-parser: 5.2.3 ws: 8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10) xmlhttprequest-ssl: 2.1.2 @@ -13402,7 +13488,7 @@ snapshots: '@es-joy/jsdoccomment': 0.46.0 are-docs-informative: 0.0.2 comment-parser: 1.4.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) escape-string-regexp: 4.0.0 eslint: 8.57.1 espree: 10.4.0 @@ -13516,7 +13602,7 @@ snapshots: ajv: 6.14.0 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -13637,8 +13723,8 @@ snapshots: ethereum-cryptography@2.2.1: dependencies: - '@noble/curves': 1.4.2 - '@noble/hashes': 1.4.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 '@scure/bip32': 1.4.0 '@scure/bip39': 1.3.0 @@ -14187,7 +14273,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -14199,10 +14285,10 @@ snapshots: transitivePeerDependencies: - debug - https-proxy-agent@7.0.6: + https-proxy-agent@7.0.6(supports-color@10.2.2): dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -14258,6 +14344,8 @@ snapshots: indent-string@4.0.0: {} + index-to-position@1.2.0: {} + inflight@1.0.6: dependencies: once: 1.4.0 @@ -14581,6 +14669,8 @@ snapshots: jiti@2.6.1: {} + js-levenshtein@1.1.6: {} + js-tokens@4.0.0: {} js-yaml@3.14.2: @@ -14608,7 +14698,7 @@ snapshots: form-data: 4.0.5 html-encoding-sniffer: 4.0.0 http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 + https-proxy-agent: 7.0.6(supports-color@10.2.2) is-potential-custom-element-name: 1.0.1 nwsapi: 2.2.23 parse5: 7.3.0 @@ -14645,6 +14735,18 @@ snapshots: json-rpc-random-id@1.0.1: {} + json-schema-to-typescript@15.0.4: + dependencies: + '@apidevtools/json-schema-ref-parser': 11.9.3 + '@types/json-schema': 7.0.15 + '@types/lodash': 4.17.24 + is-glob: 4.0.3 + js-yaml: 4.1.1 + lodash: 4.17.23 + minimist: 1.2.8 + prettier: 3.3.3 + tinyglobby: 0.2.17 + json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} @@ -15779,7 +15881,7 @@ snapshots: micromark@3.2.0: dependencies: '@types/debug': 4.1.12 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) decode-named-character-reference: 1.3.0 micromark-core-commonmark: 1.1.0 micromark-factory-space: 1.1.0 @@ -15801,7 +15903,7 @@ snapshots: micromark@4.0.2: dependencies: '@types/debug': 4.1.12 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 @@ -16255,6 +16357,16 @@ snapshots: transitivePeerDependencies: - encoding + openapi-typescript@7.13.0(typescript@5.9.3): + dependencies: + '@redocly/openapi-core': 1.34.15(supports-color@10.2.2) + ansi-colors: 4.1.3 + change-case: 5.4.4 + parse-json: 8.3.0 + supports-color: 10.2.2 + typescript: 5.9.3 + yargs-parser: 21.1.1 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -16312,7 +16424,7 @@ snapshots: dependencies: '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 - '@noble/curves': 1.9.1 + '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 @@ -16327,7 +16439,7 @@ snapshots: dependencies: '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 - '@noble/curves': 1.9.1 + '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 @@ -16342,7 +16454,7 @@ snapshots: dependencies: '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 - '@noble/curves': 1.9.1 + '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 @@ -16504,6 +16616,12 @@ snapshots: lines-and-columns: 2.0.4 type-fest: 3.13.1 + parse-json@8.3.0: + dependencies: + '@babel/code-frame': 7.29.0 + index-to-position: 1.2.0 + type-fest: 4.41.0 + parse-ms@4.0.0: {} parse-path@7.1.0: @@ -16603,6 +16721,8 @@ snapshots: dependencies: irregular-plurals: 2.0.0 + pluralize@8.0.0: {} + pngjs@5.0.0: {} pony-cause@2.1.11: {} @@ -17181,7 +17301,7 @@ snapshots: socket.io-client@4.8.3(bufferutil@4.1.0)(utf-8-validate@5.0.10): dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) engine.io-client: 6.6.4(bufferutil@4.1.0)(utf-8-validate@5.0.10) socket.io-parser: 4.2.5 transitivePeerDependencies: @@ -17192,14 +17312,14 @@ snapshots: socket.io-parser@4.2.5: dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color socks-proxy-agent@8.0.5: dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) socks: 2.8.7 transitivePeerDependencies: - supports-color @@ -17406,6 +17526,8 @@ snapshots: superstruct@2.0.2: {} + supports-color@10.2.2: {} + supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -17595,7 +17717,7 @@ snapshots: tuf-js@2.2.1: dependencies: '@tufjs/models': 2.0.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) make-fetch-happen: 13.0.1 transitivePeerDependencies: - supports-color @@ -17647,6 +17769,8 @@ snapshots: type-fest@3.13.1: {} + type-fest@4.41.0: {} + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -17758,7 +17882,7 @@ snapshots: '@types/node': 22.19.15 '@types/unist': 3.0.3 concat-stream: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) extend: 3.0.2 glob: 10.5.0 ignore: 6.0.2 @@ -17900,6 +18024,8 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + uri-js-replace@1.0.1: {} + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -18012,7 +18138,7 @@ snapshots: viem@2.46.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.22.4): dependencies: - '@noble/curves': 1.9.1 + '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 @@ -18029,7 +18155,7 @@ snapshots: viem@2.46.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.4.3): dependencies: - '@noble/curves': 1.9.1 + '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 @@ -18046,7 +18172,7 @@ snapshots: viem@2.46.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76): dependencies: - '@noble/curves': 1.9.1 + '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 @@ -18063,7 +18189,7 @@ snapshots: viem@2.46.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.4.3): dependencies: - '@noble/curves': 1.9.1 + '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 @@ -18369,6 +18495,8 @@ snapshots: yallist@5.0.0: {} + yaml-ast-parser@0.0.43: {} + yaml@1.10.2: {} yaml@2.3.1: {} diff --git a/turbo.json b/turbo.json index 3642a69139..3214ffa74a 100644 --- a/turbo.json +++ b/turbo.json @@ -9,6 +9,11 @@ "clean": { "cache": false }, + "generate": { + "dependsOn": ["^build"], + "outputs": ["src/generated/**"], + "cache": false + }, "test": { "env": ["VITEST_SEPOLIA_FORK_URL"], "dependsOn": ["^build"],