# Authentication Source: https://developers.avacloud.io/avacloud-sdk/authentication ### Per-Client Security Schemes This SDK supports the following security scheme globally: | Name | Type | Scheme | | -------- | ------ | ------- | | `apiKey` | apiKey | API key | The AvaCloud SDK can be used without an API key, but rate limits will be lower. Adding an API key allows for higher rate limits. To get an API key, create one via [AvaCloud](https://app.avacloud.io/) and securely store it. Whether or not you use an API key, you can still interact with the SDK effectively, but the API key provides performance benefits for higher request volumes. ```javascript import { AvaCloudSDK } from "@avalabs/avacloud-sdk"; const avaCloudSDK = new AvaCloudSDK({ apiKey: "", chainId: "43114", network: "mainnet", }); async function run() { const result = await avaCloudSDK.metrics.healthCheck.metricsHealthCheck(); // Handle the result console.log(result); } run(); ``` Never hardcode your API key directly into your code. Instead, securely store it and retrieve it from an environment variable, a secrets manager, or a dedicated configuration storage mechanism. This ensures that sensitive information remains protected and is not exposed in version control or publicly accessible code. # Custom HTTP Client Source: https://developers.avacloud.io/avacloud-sdk/custom-http The TypeScript SDK makes API calls using an HTTPClient that wraps the native [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). This client is a thin wrapper around `fetch` and provides the ability to attach hooks around the request lifecycle that can be used to modify the request or handle errors and response. The `HTTPClient` constructor takes an optional `fetcher` argument that can be used to integrate a third-party HTTP client or when writing tests to mock out the HTTP client and feed in fixtures. The following example shows how to use the `beforeRequest` hook to to add a custom header and a timeout to requests and how to use the `requestError` hook to log errors: ```javascript import { AvaCloudSDK } from "@avalabs/avacloud-sdk"; import { HTTPClient } from "@avalabs/avacloud-sdk/lib/http"; const httpClient = new HTTPClient({ // fetcher takes a function that has the same signature as native `fetch`. fetcher: (request) => { return fetch(request); } }); httpClient.addHook("beforeRequest", (request) => { const nextRequest = new Request(request, { signal: request.signal || AbortSignal.timeout(5000) }); nextRequest.headers.set("x-custom-header", "custom value"); return nextRequest; }); httpClient.addHook("requestError", (error, request) => { console.group("Request Error"); console.log("Reason:", `${error}`); console.log("Endpoint:", `${request.method} ${request.url}`); console.groupEnd(); }); const sdk = new AvaCloudSDK({ httpClient }); ``` # Error Handling Source: https://developers.avacloud.io/avacloud-sdk/error All SDK methods return a response object or throw an error. If Error objects are specified in your OpenAPI Spec, the SDK will throw the appropriate Error type. | Error Object | Status Code | Content Type | | :------------------------- | :---------- | :--------------- | | errors.BadRequest | 400 | application/json | | errors.Unauthorized | 401 | application/json | | errors.Forbidden | 403 | application/json | | errors.NotFound | 404 | application/json | | errors.TooManyRequests | 429 | application/json | | errors.InternalServerError | 500 | application/json | | errors.BadGateway | 502 | application/json | | errors.ServiceUnavailable | 503 | application/json | | errors.SDKError | 4xx-5xx | / | Validation errors can also occur when either method arguments or data returned from the server do not match the expected format. The SDKValidationError that is thrown as a result will capture the raw value that failed validation in an attribute called `rawValue`. Additionally, a `pretty()` method is available on this error that can be used to log a nicely formatted string since validation errors can list many issues and the plain error string may be difficult read when debugging. ```javascript import { AvaCloudSDK } from "@avalabs/avacloud-sdk"; import { BadGateway, BadRequest, Forbidden, InternalServerError, NotFound, SDKValidationError, ServiceUnavailable, TooManyRequests, Unauthorized, } from "@avalabs/avacloud-sdk/models/errors"; const avaCloudSDK = new AvaCloudSDK({ apiKey: "", chainId: "43114", network: "mainnet", }); async function run() { try { await avaCloudSDK.data.nfts.reindexNft({ address: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E", tokenId: "145", }); } catch (err) { switch (true) { case err instanceof SDKValidationError: { // Validation errors can be pretty-printed console.error(err.pretty()); // Raw value may also be inspected console.error(err.rawValue); return; } case err instanceof BadRequest: { // Handle err.data$: BadRequestData console.error(err); return; } case err instanceof Unauthorized: { // Handle err.data$: UnauthorizedData console.error(err); return; } case err instanceof Forbidden: { // Handle err.data$: ForbiddenData console.error(err); return; } case err instanceof NotFound: { // Handle err.data$: NotFoundData console.error(err); return; } case err instanceof TooManyRequests: { // Handle err.data$: TooManyRequestsData console.error(err); return; } case err instanceof InternalServerError: { // Handle err.data$: InternalServerErrorData console.error(err); return; } case err instanceof BadGateway: { // Handle err.data$: BadGatewayData console.error(err); return; } case err instanceof ServiceUnavailable: { // Handle err.data$: ServiceUnavailableData console.error(err); return; } default: { throw err; } } } } run(); ``` # Getting Started Source: https://developers.avacloud.io/avacloud-sdk/getting-started ### AvaCloud SDK The AvaCloud SDK provides web3 application developers with multi-chain data related to Avalanche's primary network, Avalanche L1s, and Ethereum. With the Data API, you can easily build products that leverage real-time and historical transaction and transfer history, native and token balances, and various types of token metadata. The SDK is currently available in TypeScript, with more languages coming soon. If you are interested in a language that is not listed, please reach out to us in the [#dev-tools](https://discord.com/channels/578992315641626624/1280920394236297257) channel in the [Avalanche Discord](https://discord.gg/avax). [https://www.npmjs.com/package/@avalabs/avacloud-sdk](https://www.npmjs.com/package/@avalabs/avacloud-sdk) [https://github.com/ava-labs/avacloud-sdk-typescript?tab=readme-ov-file#-avacloud-sdk-typescript-](https://github.com/ava-labs/avacloud-sdk-typescript?tab=readme-ov-file#-avacloud-sdk-typescript-) ### SDK Installation ```npm NPM npm add @avalabs/avacloud-sdk ``` ```pnpm PNPM pnpm add @avalabs/avacloud-sdk ``` ```bun Bun bun add @avalabs/avacloud-sdk ``` ```yarn Yarn yarn add @avalabs/avacloud-sdk zod # Note that Yarn does not install peer dependencies automatically. You will need # to install zod as shown above. ``` ### SDK Example Usage ```javascript import { AvaCloudSDK } from "@avalabs/avacloud-sdk"; const avaCloudSDK = new AvaCloudSDK({ apiKey: "", chainId: "43114", network: "mainnet", }); async function run() { const result = await avaCloudSDK.metrics.healthCheck.metricsHealthCheck(); // Handle the result console.log(result); } run(); ``` Refer to the code samples provided for each route to see examples of how to use them in the SDK. Explore routes here [Data API](/data-api/health-check/get-the-health-of-the-service), [Metrics API](/metrics-api/health-check/get-the-health-of-the-service) & [Webhooks API](/webhooks-api/webhooks/list-webhooks). # Global Parameters Source: https://developers.avacloud.io/avacloud-sdk/global-parameters Certain parameters are configured globally. These parameters may be set on the SDK client instance itself during initialization. When configured as an option during SDK initialization, These global values will be used as defaults on the operations that use them. When such operations are called, there is a place in each to override the global value, if needed. For example, you can set `chainId` to `43114` at SDK initialization and then you do not have to pass the same value on calls to operations like getBlock. But if you want to do so you may, which will locally override the global setting. See the example code below for a demonstration. ### Available Globals The following global parameters are available. | Name | Type | Required | Description | | :-------- | :---------------------------- | :------- | :------------------------------------------------------- | | `chainId` | string | No | A supported EVM chain id, chain alias, or blockchain id. | | `network` | components.GlobalParamNetwork | No | A supported network type, either mainnet or a testnet. | Example ```javascript import { AvaCloudSDK } from "@avalabs/avacloud-sdk"; const avaCloudSDK = new AvaCloudSDK({ apiKey: "", chainId: "43114", // Sets chainId globally, will be used if not passed during method call. network: "mainnet", }); async function run() { const result = await avaCloudSDK.data.evm.blocks.getBlock({ blockId: "0x17533aeb5193378b9ff441d61728e7a2ebaf10f61fd5310759451627dfca2e7c", chainId: "", // Override the globally set chain id. }); // Handle the result console.log(result) } run(); ``` # Pagination Source: https://developers.avacloud.io/avacloud-sdk/pagination Some of the endpoints in this SDK support pagination. To use pagination, you make your SDK calls as usual, but the returned response object will also be an async iterable that can be consumed using the `for await...of` syntax. Here's an example of one such pagination call: ```javascript import { AvaCloudSDK } from "@avalabs/avacloud-sdk"; const avaCloudSDK = new AvaCloudSDK({ apiKey: "", chainId: "43114", network: "mainnet", }); async function run() { const result = await avaCloudSDK.metrics.evm.chains.listChains({ network: "mainnet", }); for await (const page of result) { // Handle the page console.log(page); } } run(); ``` # Retries Source: https://developers.avacloud.io/avacloud-sdk/retries Some of the endpoints in this SDK support retries. If you use the SDK without any configuration, it will fall back to the default retry strategy provided by the API. However, the default retry strategy can be overridden on a per-operation basis, or across the entire SDK. To change the default retry strategy for a single API call, simply provide a retryConfig object to the call: ```javascript import { AvaCloudSDK } from "@avalabs/avacloud-sdk"; const avaCloudSDK = new AvaCloudSDK({ apiKey: "", chainId: "43114", network: "mainnet", }); async function run() { const result = await avaCloudSDK.metrics.healthCheck.metricsHealthCheck({ retries: { strategy: "backoff", backoff: { initialInterval: 1, maxInterval: 50, exponent: 1.1, maxElapsedTime: 100, }, retryConnectionErrors: false, }, }); // Handle the result console.log(result); } run(); ``` If you'd like to override the default retry strategy for all operations that support retries, you can provide a retryConfig at SDK initialization: ```javascript import { AvaCloudSDK } from "@avalabs/avacloud-sdk"; const avaCloudSDK = new AvaCloudSDK({ retryConfig: { strategy: "backoff", backoff: { initialInterval: 1, maxInterval: 50, exponent: 1.1, maxElapsedTime: 100, }, retryConnectionErrors: false, }, apiKey: "", chainId: "43114", network: "mainnet", }); async function run() { const result = await avaCloudSDK.metrics.healthCheck.metricsHealthCheck(); // Handle the result console.log(result); } run(); ``` # Changelog Source: https://developers.avacloud.io/changelog/changelog ### Jan 08th, 2025 **Signature Aggregator Endpoint Update** ![Aggregated Transactions & Blocks](https://mintlify.s3.us-west-1.amazonaws.com/avalabs-47ea3976/images/signature-aggregator.png) 📌 The `network` parameter has been added, allowing you to select between the following networks: * `mainnet` * `testnet` (Fuji) This update allows you to aggregate signatures on either the `mainnet` or `Fuji testnet`, providing flexibility in signature aggregation depending on your environment. Try it out [here](/data-api/signature-aggregator/aggregate-signatures)! *** ### Jan 08th, 2025 **🚀 New API Endpoints: Aggregated Transactions & Blocks Across L1 Chains & Avalanche C-Chain** ![Aggregated Transactions & Blocks](https://mintlify.s3.us-west-1.amazonaws.com/avalabs-47ea3976/images/aggregated-blocks-transactions.png) We're excited to introduce **two new API endpoints** that provide **aggregated transaction and block data** across **all supported L1 chains and the Avalanche C-Chain**! These endpoints allow developers to **query, filter, and sort** blockchain data efficiently, unlocking powerful insights across multiple chains. **📌 Get Started** * [List Latest Blocks for All Supported EVM Chains](https://developers.avacloud.io/data-api/evm-chains/list-latest-blocks-for-all-supported-evm-chains) * [List Latest Transactions for All Supported EVM Chains](https://developers.avacloud.io/data-api/evm-chains/list-latest-transactions-for-all-supported-evm-chains) These enhancements **simplify multi-chain data retrieval**, making it easier for developers to **build cross-chain analytics, wallets, and monitoring tools**. Try them out today and streamline your blockchain data integration! 🚀 *** ### Dec 20th, 2024 **Token Reputation Analysis 🛡️🔍** ![Token Reputation Analysis](https://mintlify.s3.us-west-1.amazonaws.com/avalabs-47ea3976/images/token-reputation.png) We’re thrilled to introduce Token Reputation Analysis, a new feature for identifying potential security risks with ERC20 tokens on the Avalanche C-Chain! This update adds a new field, `tokenReputation`, to the [List ERC-20 balances](/data-api/evm-balances/list-erc-20-balances) response. The field categorizes tokens into the following reputations: * `Benign`: Tokens considered safe based on security analysis. * `Malicious`: Tokens flagged for suspicious activity, spam, or phishing. * `null`: Reputation unknown. **Example Usage** Here’s an example API call: ```bash curl -X 'GET' \ 'https://glacier-api.avax.network/v1/chains/43114/addresses/0x51a679853D9582d29FF9e23ae336a0947BD0f337/balances:listErc20?pageSize=10&filterSpamTokens=true¤cy=usd' \ -H 'accept: application/json' | jq ``` As you can see in the response, the `$AVA` token is flagged as `Malicious`: ```json { "erc20TokenBalances": [ { "ercType": "ERC-20", "chainId": "43114", "address": "0x397e48aF37b7d7660D0Aee74c35b2218D7EFca12", "name": "$AVA (https://avalaunch.farm)", "symbol": "$AVA", "decimals": 2, "balance": "8200000", "tokenReputation": "Malicious" }, { "ercType": "ERC-20", "chainId": "43114", "address": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E", "name": "USD Coin", "symbol": "USDC", "decimals": 6, "balance": "1515448052896", "tokenReputation": "Benign" } ] } ``` Try it out [here](/data-api/evm-balances/list-erc-20-balances)! *** ### Nov 25th, 2024 **Avalanche9000 (Etna Upgrade 🌋)** ![Avalanche9000](https://mintlify.s3.us-west-1.amazonaws.com/avalabs-47ea3976/images/avalanche9000.jpeg) **New endpoint to list L1 validators:** * Added new endpoint to [list all or specific L1 validators](/data-api/primary-network/list-l1-validators) * Filters include `L1ValidationID`, `SubnetID`, `NodeID`, and `IncludeInactiveL1Validators`. **Updated transactions endpoint:** * [List latest transactions on the primary network](/data-api/primary-network-transactions/list-latest-transactions) now supports `l1ValidationID` to fetch transactions linked to specific L1 validators (e.g., `ConvertSubnetToL1Tx`). * L1 transactions are sorted in descending order with additional filters like `timestamp` and `txTypes`. **Enhanced transaction properties:** * P-Chain Transaction responses now include: * L1 validator details (`validationID`, `nodeID`, `weight`, `balances`, etc.). * Burned AVAX details for increasing L1 validator balance. * Validator manager details (`BlockchainID` and `ContractAddress`). **New block properties:** * P-Chain blocks now include: * `ActiveL1Validators` (total active L1 validators). * `L1ValidatorsAccruedFees` (fees from active L1 validators). **New subnet properties:** * Subnet details now have: * `IsL1` to indicate if a subnet has been converted to an L1. * Validator manager details for L1 subnets. These changes support seamless management and visibility of L1 validators introduced in the Etna upgrade. For more details, see [here](/data-api/etna) *** ### Oct 25th, 2024 **Data API new endpoint - Listing networks an address has interacted with** Returns a list of all networks on which an EVM address has had activity, filtering out networks with no activity for the provided address. Endpoint: `GET https://glacier-api.avax.network/v1/chains/address/{address}` [Gets the list of chains an address has interacted with](/data-api/evm-chains/get-chains-for-address). Example response: ```json { "indexedChains": [ { "chainId": "43114", "status": "OK", "chainName": "Avalanche (C-Chain)", "description": "The Contract Chain (C-Chain) runs on an Ethereum Virtual Machine and is used to deploy smart contracts and connect to dApps.", "platformChainId": "2q9e4r6Mu3U68nU1fYjgbR6JvwrRx36CohpAX5UQxse55x1Q5", "subnetId": "11111111111111111111111111111111LpoYY", "vmId": "mgj786NP7uDwBCcq6YwThhaN8FLyybkCa4zBWTQbNgmK6k9A6", "vmName": "EVM", "explorerUrl": "https://subnets.avax.network/c-chain", "rpcUrl": "https://api.avax.network/ext/bc/C/rpc", "wsUrl": "wss://api.avax.network/ext/bc/C/ws", "isTestnet": false, "utilityAddresses": { "multicall": "0xed386Fe855C1EFf2f843B910923Dd8846E45C5A4" }, "networkToken": { "name": "Avalanche", "symbol": "AVAX", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/5VHupNKwnDYJvqMENeV7iJ/3e4b8ff10b69bfa31e70080a4b142cd0/avalanche-avax-logo.svg", "description": "AVAX is the native utility token of Avalanche. It’s a hard-capped, scarce asset that is used to pay for fees, secure the platform through staking, and provide a basic unit of account between the multiple Subnets created on Avalanche." }, "chainLogoUri": "https://images.ctfassets.net/gcj8jwzm6086/5VHupNKwnDYJvqMENeV7iJ/3e4b8ff10b69bfa31e70080a4b142cd0/avalanche-avax-logo.svg", "private": false, "enabledFeatures": [ "nftIndexing", "webhooks", "teleporter" ] }, { "chainId": "43113", "status": "OK", "chainName": "Avalanche (C-Chain)", "description": "The Contract Chain on Avalanche's test subnet.", "platformChainId": "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp", "subnetId": "11111111111111111111111111111111LpoYY", "vmId": "mgj786NP7uDwBCcq6YwThhaN8FLyybkCa4zBWTQbNgmK6k9A6", "vmName": "EVM", "explorerUrl": "https://subnets-test.avax.network/c-chain", "rpcUrl": "https://api.avax-test.network/ext/bc/C/rpc", "wsUrl": "wss://api.avax-test.network/ext/bc/C/ws", "isTestnet": true, "utilityAddresses": { "multicall": "0xE898101ffEF388A8DA16205249a7E4977d4F034c" }, "networkToken": { "name": "Avalanche", "symbol": "AVAX", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/5VHupNKwnDYJvqMENeV7iJ/3e4b8ff10b69bfa31e70080a4b142cd0/avalanche-avax-logo.svg", "description": "AVAX is the native utility token of Avalanche. It’s a hard-capped, scarce asset that is used to pay for fees, secure the platform through staking, and provide a basic unit of account between the multiple Subnets created on Avalanche." }, "chainLogoUri": "https://images.ctfassets.net/gcj8jwzm6086/5VHupNKwnDYJvqMENeV7iJ/3e4b8ff10b69bfa31e70080a4b142cd0/avalanche-avax-logo.svg", "private": false, "enabledFeatures": [ "nftIndexing", "webhooks", "teleporter" ] }, { "chainId": "779672", "status": "OK", "chainName": "Dispatch L1", "description": "Environment for testing Avalanche Warp Messaging and Teleporter.", "platformChainId": "2D8RG4UpSXbPbvPCAWppNJyqTG2i2CAXSkTgmTBBvs7GKNZjsY", "subnetId": "7WtoAMPhrmh5KosDUsFL9yTcvw7YSxiKHPpdfs4JsgW47oZT5", "vmId": "mDtV8ES8wRL1j2m6Kvc1qRFAvnpq4kufhueAY1bwbzVhk336o", "vmName": "EVM", "explorerUrl": "https://subnets-test.avax.network/dispatch", "rpcUrl": "https://subnets.avax.network/dispatch/testnet/rpc", "isTestnet": true, "utilityAddresses": { "multicall": "0xb35f163b70AbABeE69cDF40bCDA94df2c37d9df8" }, "networkToken": { "name": "DIS", "symbol": "DIS", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/60XrKdf99PqQKrHiuYdwTE/908622f5204311dbb11be9c6008ead44/Dispatch_Subnet_Logo.png", "description": "" }, "chainLogoUri": "https://images.ctfassets.net/gcj8jwzm6086/60XrKdf99PqQKrHiuYdwTE/908622f5204311dbb11be9c6008ead44/Dispatch_Subnet_Logo.png", "private": false, "enabledFeatures": [ "teleporter" ] }, { "chainId": "173750", "status": "OK", "chainName": "Echo L1", "description": "Environment for testing Avalanche Warp Messaging and Teleporter.", "platformChainId": "98qnjenm7MBd8G2cPZoRvZrgJC33JGSAAKghsQ6eojbLCeRNp", "subnetId": "i9gFpZQHPLcGfZaQLiwFAStddQD7iTKBpFfurPFJsXm1CkTZK", "vmId": "meq3bv7qCMZZ69L8xZRLwyKnWp6chRwyscq8VPtHWignRQVVF", "vmName": "EVM", "explorerUrl": "https://subnets-test.avax.network/echo", "rpcUrl": "https://subnets.avax.network/echo/testnet/rpc", "isTestnet": true, "utilityAddresses": { "multicall": "0x0E3a5F409eF471809cc67311674DDF7572415682" }, "networkToken": { "name": "ECH", "symbol": "ECH", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/7kyTY75fdtnO6mh7f0osix/4c92c93dd688082bfbb43d5d910cbfeb/Echo_Subnet_Logo.png", "description": "" }, "chainLogoUri": "https://images.ctfassets.net/gcj8jwzm6086/7kyTY75fdtnO6mh7f0osix/4c92c93dd688082bfbb43d5d910cbfeb/Echo_Subnet_Logo.png", "private": false, "enabledFeatures": [ "teleporter" ] } ], "unindexedChains": [] } ``` *** ### Sep 12th, 2024 **Data API new endpoint - List teleporter messages by address** Endpoint: `GET https://glacier-api.avax.network/v1/teleporter/addresses/{address}/messages` [Lists teleporter messages by address](/data-api/teleporter/list-teleporter-messages-address). Ordered by timestamp in descending order. Example response: ```json { "messages": [{ "messageId": "25e7bcf7304516a24f5ee597048ada3680dfa3264b27722b46b399da2180dea6", "teleporterContractAddress": "0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf", "sourceBlockchainId": "2q9e4r6Mu3U68nU1fYjgbR6JvwrRx36CohpAX5UQxse55x1Q5", "destinationBlockchainId": "75babf9b4db10c46cd1c4cc28e199cc4acf4c64f78327ff6cda26b8785a7bb5d", "sourceEvmChainId": "43114", "destinationEvmChainId": "", "messageNonce": "29", "from": "0x573e623caCfDe4427C460Fc408aDD5AB21220FD7", "to": "0xB324bf38e6aFf06670EF649077062A7563b87fC5", "data": "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000006626f6272696b0000000000000000000000000000000000000000000000000000", "messageExecuted": false, "receipts": [], "receiptDelivered": false, "rewardDetails": { "value": "0", "address": "0x0000000000000000000000000000000000000000", "ercType": "ERC-20", "name": "", "symbol": "", "decimals": 0 }, "status": "pending", "sourceTransaction": { "txHash": "0x7f5258b78964bc0f7b7abd1b3b99fb8665acb3d67e5ebe8fdf1b9e6ae6402b2a", "timestamp": 1722571442, "gasSpent": "3338675000000000" } }, { "messageId": "2c56bfe4c816ca2d8241bf7a76ade09cb1cc9ab52dbc7b774184ad7cc9fba2a8", "teleporterContractAddress": "0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf", "sourceBlockchainId": "2q9e4r6Mu3U68nU1fYjgbR6JvwrRx36CohpAX5UQxse55x1Q5", "destinationBlockchainId": "2q9e4r6Mu3U68nU1fYjgbR6JvwrRx36CohpAX5UQxse55x1Q5", "sourceEvmChainId": "43114", "destinationEvmChainId": "43114", "messageNonce": "28", "from": "0x573e623caCfDe4427C460Fc408aDD5AB21220FD7", "to": "0xB324bf38e6aFf06670EF649077062A7563b87fC5", "data": "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000006626f6272696b0000000000000000000000000000000000000000000000000000", "messageExecuted": false, "receipts": [], "receiptDelivered": false, "rewardDetails": { "value": "0", "address": "0x0000000000000000000000000000000000000000", "ercType": "ERC-20", "name": "", "symbol": "", "decimals": 0 }, "status": "pending", "sourceTransaction": { "txHash": "0xee1b6a56dca07cc35d01a912d0e80b1124f8986b1d375534ef651a822798e509", "timestamp": 1722570309, "gasSpent": "3338675000000000" } }] } ``` *** ### August 6th, 2024 **Data API new endpoint- Get L1 details by `subnetID`** Endpoint: `GET https://glacier-api.avax.network/v1/networks/{network}/subnets/{subnetId}` This endpoint retrieves detailed information about a specific L1/subnet registered on the network. By providing the network type (mainnet or a testnet) and the L1 ID, you can fetch various details including the subnet’s creation timestamp, ownership information, and associated blockchains. Example response: ```JSON { "createBlockTimestamp": 1599696000, "createBlockIndex": "-1", "subnetId": "11111111111111111111111111111111LpoYY", "ownerAddresses": [ "" ], "threshold": 0, "locktime": 0, "subnetOwnershipInfo": { "addresses": [ "0" ], "locktime": 0, "threshold": null }, "blockchains": [ { "blockchainId": "11111111111111111111111111111111LpoYY" }, { "blockchainId": "2oYMBNV4eNHyqk2fjjV5nVQLDbtmNJzq5s3qs3Lo6ftnC6FByM" }, { "blockchainId": "2q9e4r6Mu3U68nU1fYjgbR6JvwrRx36CohpAX5UQxse55x1Q5" } ] } ``` *** ### May 21st, 2024 **Filter spam tokens and new endpoints for the primary network** The following improvements have been made to the Glacier API: * **EVM**
Remove Spam Tokens from Balances Endpoint Users can now pass in an optional query parameter `filterSpamTokens` when getting balances for a particular address to filter out balances of tokens that we've determined to be spam. By default, the route will now filter spam tokens unless `filterSpamTokens=false`. Try it out [here](/data-api/evm-balances/list-erc-20-balances)! * **Primary Network**
In the [List Validators](/data-api/primary-network/list-validators) endpoint, users can now sort validators by Block Index, Delegation Capacity, Time Remaining, Delegation Fee, or Uptime Performance. Users can also filter by validator uptime performance using `minUptimePerformance` and `maxUptimePerformance` and by fee percentage using `minFeePercentage` and \`maxFeePercentage. * **Webhooks**
A new [API endpoint](/webhooks-api/webhooks/list-adresses-by-webhook) has been added to enable users to list all addresses associated with a webhook. *** ### Aug 20th, 2024 **Webhook service launched** With Glacier Webhooks, you can monitor real-time events on the Avalanche C-chain and L1s. For example, you can monitor smart contract events, track NFT transfers, and observe wallet-to-wallet transactions. ![webhooks](https://mintlify.s3.us-west-1.amazonaws.com/avalabs-47ea3976/images/webhooks.png) **Key Features:**
* **Real-time notifications**: Receive immediate updates on specified on-chain activities without polling. * **Customizable**: Specify the desired event type to listen for, customizing notifications according to individual requirements. * **Secure**: Employ shared secrets and signature-based verification to guarantee that notifications originate from a trusted source. * **Broad Coverage**: Support for C-chain mainnet, testnet, and L1s within the Avalanche ecosystem, ensuring wide-ranging monitoring capabilities. **Use cases**
* **NFT Marketplace Transactions**: Get alerts for NFT minting, transfers, auctions, bids, sales, and other interactions within NFT marketplaces. * **Wallet Notifications**: Receive alerts when an address performs actions such as sending, receiving, swapping, or burning assets. * **DeFi Activities**: Receive notifications for various DeFi activities such as liquidity provisioning, yield farming, borrowing, lending, and liquidations. For further details, visit our: * [Overview](/webhooks-api/overview) * [Getting Started](/webhooks-api/getting-started) # How to get all transactions of an address Source: https://developers.avacloud.io/data-api/address-transactions This guide will walk you through how to retrieve all transactions associated with a specific wallet address on the C-chain network using the Data API. ### Step 1: Setup your account First, ensure that you have set up [AvaCloud](https://app.avacloud.io/) and have access to your API key. If you’re new to Avacloud, create an account and obtain an API key. ### Step 2: Get All Transactions for an Address To get all transactions for a specific address you can use [list transactions](/data-api/evm-transactions/list-transactions) endpoint. You’ll need to specify the `chainId` and the `address` for which you want to retrieve the transactions. Here’s how you can do it: ```javascript AvacloudSDK import { AvaCloudSDK } from "@avalabs/avacloud-sdk"; const avaCloudSDK = new AvaCloudSDK({ glacierApiKey: "", chainId: "43114", network: "mainnet", }); async function run() { const result = await avaCloudSDK.data.evm.transactions.listTransactions({ pageSize: 10, address: "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", sortOrder: "asc", }); console.log(JSON.stringify(result, null, 2)); } run(); ``` ```bash cURL curl --request GET \ --url https://glacier-api.avax.network/v1/chains/43114/addresses/0x71C7656EC7ab88b098defB751B7401B5f6d8976F/transactions \ --header 'x-glacier-api-key: ' ``` ### Step 3: Run the script Once you’ve copied the code into your preferred developer tool, you can run it using the following commands: ```bash node index.js ``` After running the script, you should see a JSON response similar to this in your terminal: ```json { "transactions": [ { "nativeTransaction": { "blockNumber": "43281797", "blockIndex": 3, "blockHash": "0x85ad9ece9c384554f100318c7d88834ebacf5c9dd970d1406297eb4c90ee850f", "txHash": "0x4dde404e7ac7fb9eb10ab780fba9715ef07105312aa3a6367cfc2322cbd352fe", "txStatus": "1", "txType": 2, "gasLimit": "92394", "gasUsed": "61126", "gasPrice": "26500000000", "nonce": "16", "blockTimestamp": 1711218299, "from": { "address": "0x5AEdcCaeCA2cb3f87a90713c83872f7515e19c90" }, "to": { "address": "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7", "name": "TetherToken", "symbol": "USDT", "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/4ac7cb0c-5260-473b-a4bc-b809801aa5da/49d45340a82166bdb26fce4d3e62ce65/43114-0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7.png" }, "method": { "callType": "CONTRACT_CALL", "methodHash": "0xa9059cbb" }, "value": "0" }, "erc20Transfers": [ { "from": { "address": "0x5AEdcCaeCA2cb3f87a90713c83872f7515e19c90" }, "to": { "address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" }, "logIndex": 10, "value": "400000", "erc20Token": { "ercType": "ERC-20", "address": "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7", "name": "TetherToken", "symbol": "USDT", "decimals": 6, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/4ac7cb0c-5260-473b-a4bc-b809801aa5da/49d45340a82166bdb26fce4d3e62ce65/43114-0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7.png", "price": { "value": 0.999436, "currencyCode": "usd" } } } ] }, { "nativeTransaction": { "blockNumber": "26002777", "blockIndex": 0, "blockHash": "0x83c8d5bb1b885d1efaf116da6a9d776088d19c9fdfd06a71d16156c80b339261", "txHash": "0xc96e00ce365f2fae67f940985fc8b9af97a051f5bf0f29c891205ca1ae3287d4", "txStatus": "1", "txType": 0, "gasLimit": "21000", "gasUsed": "21000", "gasPrice": "27500000000", "nonce": "11", "blockTimestamp": 1675878866, "from": { "address": "0x444782F140e31B5687d166FA077C3049062911Ba" }, "to": { "address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" }, "method": { "callType": "NATIVE_TRANSFER", "methodHash": "", "methodName": "Native Transfer" }, "value": "3005020000000000" } }, { "nativeTransaction": { "blockNumber": "25037477", "blockIndex": 6, "blockHash": "0x048a00b6e40ffdb2b3a4b596cfa6ee2e4479c53099f23afed3145569d2cbfb02", "txHash": "0x4c29443c0d8f08d2be1cc6c20bc7a1a05211b91340550edf26d0bd9196c593a3", "txStatus": "1", "txType": 2, "gasLimit": "31500", "gasUsed": "21000", "gasPrice": "26500000000", "nonce": "2590", "blockTimestamp": 1673917315, "from": { "address": "0x1C42F2fCc9c7F4a30dC15ACf9C047DDeCF39de06" }, "to": { "address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" }, "method": { "callType": "NATIVE_TRANSFER", "methodHash": "", "methodName": "Native Transfer" }, "value": "150000000000000000" } }, { "nativeTransaction": { "blockNumber": "23826282", "blockIndex": 0, "blockHash": "0x96caae2487206cba32000e49e2f593406981fcf26cffd646da92661ce907fc62", "txHash": "0x7aaa1beff9466f8e099b8a25e37b1f748b2623856f65cd479bd721e983ee84ac", "txStatus": "1", "txType": 0, "gasLimit": "21000", "gasUsed": "21000", "gasPrice": "31250000000", "nonce": "0", "blockTimestamp": 1671433238, "from": { "address": "0x6B69f15BCEeB1a2326De003ca97b1F61AE57b774" }, "to": { "address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" }, "method": { "callType": "NATIVE_TRANSFER", "methodHash": "", "methodName": "Native Transfer" }, "value": "57557140067572377" } }, { "nativeTransaction": { "blockNumber": "23249650", "blockIndex": 4, "blockHash": "0xf0161747357482ce078d398f55e9413ce4a4e21611b20f5488b74e4d181536bd", "txHash": "0x760ac8c147a9ec795a7695f3c3383408890f53fc23e39f43f938f513910a9612", "txStatus": "1", "txType": 2, "gasLimit": "21000", "gasUsed": "21000", "gasPrice": "26843560317", "nonce": "9", "blockTimestamp": 1670254442, "from": { "address": "0xcd661208b0138A9468D5B6E3E119215e5aA14c15" }, "to": { "address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" }, "method": { "callType": "NATIVE_TRANSFER", "methodHash": "", "methodName": "Native Transfer" }, "value": "9942019140711807" } }, { "nativeTransaction": { "blockNumber": "21989662", "blockIndex": 8, "blockHash": "0x9eefeb39b435c625cf659674df2a0d56b85b2efffb677edd8a4365d7fc39dd68", "txHash": "0x0e1f96c84ddc07d74a19ee748381048e1876bf8a706e5e8f917897f6761eef51", "txStatus": "1", "txType": 2, "gasLimit": "2146729", "gasUsed": "1431153", "gasPrice": "26000000000", "nonce": "4", "blockTimestamp": 1667660826, "from": { "address": "0x55906a1d87f7426497fDBa498B8F5edB1C741cef" }, "to": { "address": "0xF9d922c055A3f1759299467dAfaFdf43BE844f7a" }, "method": { "callType": "CONTRACT_CALL", "methodHash": "0x74a72e41" }, "value": "0" }, "erc20Transfers": [ { "from": { "address": "0xF9d922c055A3f1759299467dAfaFdf43BE844f7a" }, "to": { "address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" }, "logIndex": 33, "value": "30000000000000", "erc20Token": { "ercType": "ERC-20", "address": "0xF9d922c055A3f1759299467dAfaFdf43BE844f7a", "name": "Minereum AVAX", "symbol": "MNEAV", "decimals": 8 } } ] }, { "nativeTransaction": { "blockNumber": "17768295", "blockIndex": 3, "blockHash": "0x55f934b32644b9c6d53283ac9275747929779e38ad0687d9c8e895a8699986b2", "txHash": "0x8138fea77335fd208ec7618a67fdd3a104577e8e89a6d0665407202163ff9d07", "txStatus": "1", "txType": 2, "gasLimit": "77829", "gasUsed": "51886", "gasPrice": "26500000000", "nonce": "6", "blockTimestamp": 1658716784, "from": { "address": "0x7e31af176DA39a9986c8f5c7632178B4AcF0c868" }, "to": { "address": "0x4cb70De91e6Bb85fB132880D5Af3418477a90083" }, "method": { "callType": "CONTRACT_CALL", "methodHash": "0xa9059cbb" }, "value": "0" }, "erc20Transfers": [ { "from": { "address": "0x7e31af176DA39a9986c8f5c7632178B4AcF0c868" }, "to": { "address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" }, "logIndex": 6, "value": "50000000000000000", "erc20Token": { "ercType": "ERC-20", "address": "0x4cb70De91e6Bb85fB132880D5Af3418477a90083", "name": "Woodcut Token", "symbol": "WOOD", "decimals": 18 } } ] }, { "nativeTransaction": { "blockNumber": "17328312", "blockIndex": 0, "blockHash": "0x96c1554115937f2ea11efac5d08c9a844925dace3ff4b62679fd3183fc8c8aa9", "txHash": "0xdcc0cf0982aed703d72da1fefd686e97fa549bd3717972a547440a3abc384bfb", "txStatus": "1", "txType": 0, "gasLimit": "21000", "gasUsed": "21000", "gasPrice": "30000000000", "nonce": "3", "blockTimestamp": 1657827243, "from": { "address": "0x6ae30413ddA067f8BB2D904d630081784f4c2a3E" }, "to": { "address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" }, "method": { "callType": "NATIVE_TRANSFER", "methodHash": "", "methodName": "Native Transfer" }, "value": "3694737000000000" } }, { "nativeTransaction": { "blockNumber": "13923067", "blockIndex": 17, "blockHash": "0x22c7369d613a8ee600fa8dd0a178c575139150d18d04220633cc682465774536", "txHash": "0x9a8822afb1f082f1250ac1876223384fac8370f9dd1f785ce54c3acbcaf7341a", "txStatus": "1", "txType": 2, "gasLimit": "21000", "gasUsed": "21000", "gasPrice": "72048389636", "nonce": "1", "blockTimestamp": 1650975303, "from": { "address": "0xffc83E3777DB33ff4af4A3fB72056fF3bDF02e47" }, "to": { "address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" }, "method": { "callType": "NATIVE_TRANSFER", "methodHash": "", "methodName": "Native Transfer" }, "value": "31240000000000000" } }, { "nativeTransaction": { "blockNumber": "13922287", "blockIndex": 19, "blockHash": "0x42c6a341b8d5794b83026cd1aa63606cbeb917b2e58a017b48c8d24b69fe788c", "txHash": "0x12681543ad3f41cb2146f959528fbedea3250afbed14f152cf0ec87bce4c69c2", "txStatus": "1", "txType": 2, "gasLimit": "21000", "gasUsed": "21000", "gasPrice": "69081184341", "nonce": "9", "blockTimestamp": 1650973723, "from": { "address": "0xB30228A0FfB21f68a144Dd4f3af703ce975Cf490" }, "to": { "address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" }, "method": { "callType": "NATIVE_TRANSFER", "methodHash": "", "methodName": "Native Transfer" }, "value": "33305869282988272" } } ], "nextPageToken": "5b7c89d0-1f1b-45d1-a539-57b8e70d034f" } ``` Congratulations 🎉 You’ve successfully retrieved all transactions for a wallet address on the C-chain using the Data API! With just a few lines of code, you can now access this data easily and integrate it into your projects. # Get logs for requests made by client Source: https://developers.avacloud.io/data-api/data-api-usage-metrics/get-logs-for-requests-made-by-client get /v1/apiLogs Gets logs for requests made by client over a specified time interval for a specific organization. # Get usage metrics for the Data API Source: https://developers.avacloud.io/data-api/data-api-usage-metrics/get-usage-metrics-for-the-data-api get /v1/apiUsageMetrics Gets metrics for Data API usage over a specified time interval aggregated at the specified time-duration granularity. # null Source: https://developers.avacloud.io/data-api/data-api-usage-metrics/get-usage-metrics-for-the-rpc get /v1/rpcUsageMetrics **[Deprecated]** Gets metrics for public Subnet RPC usage over a specified time interval aggregated at the specified time-duration granularity. ⚠️ **This operation will be removed in a future release. Please use /v1/subnetRpcUsageMetrics endpoint instead**. # Get usage metrics for the Subnet RPC Source: https://developers.avacloud.io/data-api/data-api-usage-metrics/get-usage-metrics-for-the-subnet-rpc get /v1/subnetRpcUsageMetrics Gets metrics for public Subnet RPC usage over a specified time interval aggregated at the specified time-duration granularity. # Data API vs RPC Source: https://developers.avacloud.io/data-api/data-api-vs-rpc In the rapidly evolving world of Web3 development, efficiently retrieving token balances for a user's address is a fundamental requirement. Whether you're building DeFi platforms, wallets, analytics tools, or exchanges, displaying accurate token balances is crucial for user engagement and trust. A typical use case involves showing a user's token portfolio in a wallet application, in this case, we have sAvax and USDC. ![title](https://mintlify.s3.us-west-1.amazonaws.com/avalabs-47ea3976/images/wallet.png) Developers generally have two options to fetch this data: 1. **Using RPC methods to index blockchain data on their own** 2. **Leveraging an indexer provider like the Data API** While both methods aim to achieve the same goal, the Data API offers a more efficient, scalable, and developer-friendly solution. This article delves into why using the Data API is better than relying on traditional RPC (Remote Procedure Call) methods. ### What Are RPC methods and their challenges? Remote Procedure Call (RPC) methods allow developers to interact directly with blockchain nodes. One of their key advantages is that they are standardized and universally understood by blockchain developers across different platforms. With RPC, you can perform tasks such as querying data, submitting transactions, and interacting with smart contracts. These methods are typically low-level and synchronous, meaning they require a deep understanding of the blockchain’s architecture and specific command structures. You can refer to the [official documentation](https://ethereum.org/en/developers/docs/apis/json-rpc/) to gain a more comprehensive understanding of the JSON-RPC API. Here’s an example using the `eth_getBalance` method to retrieve the native balance of a wallet: ```bash curl --location 'https://api.avax.network/ext/bc/C/rpc' \ --header 'Content-Type: application/json' \ --data '{"method":"eth_getBalance","params":["0x8ae323046633A07FB162043f28Cea39FFc23B50A", "latest"],"id":1,"jsonrpc":"2.0"}' ``` This call returns the following response: ```json { "jsonrpc": "2.0", "id": 1, "result": "0x284476254bc5d594" } ``` The balance in this wallet is 2.9016 AVAX. However, despite the wallet holding multiple tokens such as USDC, the `eth_getBalance` method only returns the AVAX amount and it does so in Wei and in hexadecimal format. This is not particularly human-readable, adding to the challenge for developers who need to manually convert the balance to a more understandable format. #### No direct RPC methods to retrieve token balances Despite their utility, RPC methods come with significant limitations when it comes to retrieving detailed token and transaction data. Currently, RPC methods do not provide direct solutions for the following: * **Listing all tokens held by a wallet**: There is no RPC method that provides a complete list of ERC-20 tokens owned by a wallet. * **Retrieving all transactions for a wallet**: : There is no direct method for fetching all transactions associated with a wallet. * **Getting ERC-20/721/1155 token balances**: The `eth_getBalance` method only returns the balance of the wallet’s native token (such as AVAX on Avalanche) and cannot be used to retrieve ERC-20/721/1155 token balances. To achieve these tasks using RPC methods alone, you would need to: * **Query every block for transaction logs**: Scan the entire blockchain, which is resource-intensive and impractical. * **Parse transaction logs**: Identify and extract ERC-20 token transfer events from each transaction. * **Aggregate data**: Collect and process this data to compute balances and transaction histories. #### Manual blockchain indexing is difficult and costly Using RPC methods to fetch token balances involves an arduous process: 1. You must connect to a node and subscribe to new block events. 2. For each block, parse every transaction to identify ERC-20 token transfers involving the user's address. 3. Extract contract addresses and other relevant data from the parsed transactions. 4. Compute balances by processing transfer events. 5. Store the processed data in a database for quick retrieval and aggregation. #### Why this is difficult: * **Resource-Intensive**: Requires significant computational power and storage to process and store blockchain data. * **Time-consuming**: Processing millions of blocks and transactions can take an enormous amount of time. * **Complexity**: Handling edge cases like contract upgrades, proxy contracts, and non-standard implementations adds layers of complexity. * **Maintenance**: Keeping the indexed data up-to-date necessitates continuous synchronization with new blocks being added to the blockchain. * **High Costs**: Associated with servers, databases, and network bandwidth. ### The Data API Advantage The Data API provides a streamlined, efficient, and scalable solution for fetching token balances. Here's why it's the best choice: With a single API call, you can retrieve all ERC-20 token balances for a user's address: ```javascript avaCloudSDK.data.evm.balances.listErc20Balances({ address: "0xYourAddress" }); ``` Sample Response: ```json { "erc20TokenBalances": [ { "ercType": "ERC-20", "chainId": "43114", "address": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E", "name": "USD Coin", "symbol": "USDC", "decimals": 6, "price": { "value": 1.00, "currencyCode": "usd" }, "balance": "15000000", "balanceValue": { "currencyCode": "usd", "value": 9.6 }, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/e50058c1-2296-4e7e-91ea-83eb03db95ee/8db2a492ce64564c96de87c05a3756fd/43114-0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E.png" }, // Additional tokens... ] } ``` As you can see with a single call the API returns an array of token balances for all the wallet tokens, including: * **Token metadata**: Contract address, name, symbol, decimals. * **Balance information**: Token balance in both hexadecimal and decimal formats, Also retrieves balances of native assets like ETH or AVAX. * **Price data**: Current value in USD or other supported currencies, saving you the effort of integrating another API. * **Visual assets**: Token logo URI for better user interface integration. If you’re building a wallet, DeFi app, or any application that requires displaying balances, transaction history, or smart contract interactions, relying solely on RPC methods can be challenging. Just as there’s no direct RPC method to retrieve token balances, there’s also no simple way to fetch all transactions associated with a wallet, especially for ERC-20, ERC-721, or ERC-1155 token transfers. However, by using the Data API, you can retrieve all token transfers for a given wallet **with a single API call**, making the process much more efficient. This approach simplifies tracking and displaying wallet activity without the need to manually scan the entire blockchain. Below are two examples that demonstrate the power of the Data API: in the first, it returns all ERC transfers, including ERC-20, ERC-721, and ERC-1155 tokens, and in the second, it shows all internal transactions, such as when one contract interacts with another. [Lists ERC transfers](/data-api/evm-transactions/list-erc-transfers) for an ERC-20, ERC-721, or ERC-1155 contract address. ```javascript import { AvaCloudSDK } from "@avalabs/avacloud-sdk"; const avaCloudSDK = new AvaCloudSDK({ apiKey: "", chainId: "43114", network: "mainnet", }); async function run() { const result = await avaCloudSDK.data.evm.transactions.listTransfers({ startBlock: 6479329, endBlock: 6479330, pageSize: 10, address: "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", }); for await (const page of result) { // Handle the page console.log(page); } } run(); ``` Example response ```json { "nextPageToken": "", "transfers": [ { "blockNumber": "339", "blockTimestamp": 1648672486, "blockHash": "0x17533aeb5193378b9ff441d61728e7a2ebaf10f61fd5310759451627dfca2e7c", "txHash": "0x3e9303f81be00b4af28515dab7b914bf3dbff209ea10e7071fa24d4af0a112d4", "from": { "name": "Wrapped AVAX", "symbol": "WAVAX", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/5VHupNKwnDYJvqMENeV7iJ/fdd6326b7a82c8388e4ee9d4be7062d4/avalanche-avax-logo.svg", "address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" }, "to": { "name": "Wrapped AVAX", "symbol": "WAVAX", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/5VHupNKwnDYJvqMENeV7iJ/fdd6326b7a82c8388e4ee9d4be7062d4/avalanche-avax-logo.svg", "address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" }, "logIndex": 123, "value": "10000000000000000000", "erc20Token": { "address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", "name": "Wrapped AVAX", "symbol": "WAVAX", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/5VHupNKwnDYJvqMENeV7iJ/fdd6326b7a82c8388e4ee9d4be7062d4/avalanche-avax-logo.svg", "ercType": "ERC-20", "price": { "currencyCode": "usd", "value": "42.42" } } } ] } ``` [Returns a list of internal transactions](/data-api/evm-transactions/list-internal-transactions) for an address and chain. Filterable by block range. ```javascript import { AvaCloudSDK } from "@avalabs/avacloud-sdk"; const avaCloudSDK = new AvaCloudSDK({ apiKey: "", chainId: "43114", network: "mainnet", }); async function run() { const result = await avaCloudSDK.data.evm.transactions.listInternalTransactions({ startBlock: 6479329, endBlock: 6479330, pageSize: 10, address: "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", }); for await (const page of result) { // Handle the page console.log(page); } } run(); ``` Example response ```json { "nextPageToken": "", "transactions": [ { "blockNumber": "339", "blockTimestamp": 1648672486, "blockHash": "0x17533aeb5193378b9ff441d61728e7a2ebaf10f61fd5310759451627dfca2e7c", "txHash": "0x3e9303f81be00b4af28515dab7b914bf3dbff209ea10e7071fa24d4af0a112d4", "from": { "name": "Wrapped AVAX", "symbol": "WAVAX", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/5VHupNKwnDYJvqMENeV7iJ/fdd6326b7a82c8388e4ee9d4be7062d4/avalanche-avax-logo.svg", "address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" }, "to": { "name": "Wrapped AVAX", "symbol": "WAVAX", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/5VHupNKwnDYJvqMENeV7iJ/fdd6326b7a82c8388e4ee9d4be7062d4/avalanche-avax-logo.svg", "address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" }, "internalTxType": "UNKNOWN", "value": "10000000000000000000", "isReverted": true, "gasUsed": "", "gasLimit": "" } ] } ``` ### Conclusion Using the Data API over traditional RPC methods for fetching token balances offers significant advantages: * **Efficiency**: Retrieve all necessary information in a single API call. * **Simplicity**: Eliminates complex data processing and reduces development time. * **Scalability**: Handles large volumes of data efficiently, suitable for real-time applications. * **Comprehensive Data**: Provides enriched information, including token prices and logos. * **Reliability**: Ensures data accuracy and consistency without the need for extensive error handling. For developers building Web3 applications, leveraging the Data API is the smarter choice. It not only simplifies your codebase but also enhances the user experience by providing accurate and timely data. If you’re building cutting-edge Web3 applications, this API is the key to improving your workflow and performance. Whether you’re developing DeFi solutions, wallets, or analytics platforms, take your project to the next level. [Start today with the Data API](/data-api/getting-started) and experience the difference! # How to get all ERC20 transfers by wallet Source: https://developers.avacloud.io/data-api/erc20-transfers This guide will walk you through the process of listing all ERC-20 transfers associated with a specific wallet address on the DFK L1 network using the Data API. ### Step 1: Set Up AvaCloud First, ensure that you have set up [AvaCloud](https://app.avacloud.io/) and have access to your API key. If you’re new to Avacloud, create an account and obtain an API key. ### Step 2: Retrieve the Native Balance of an Address To obtain a list of ERC-20 transfers you can use the [List ERC-20 transfers](/data-api/evm-transactions/list-erc-20-transfers) endpoint. You’ll need to specify the `chainId` and the `address` for which you want to retrieve the balance. Here’s how you can do it: ```javascript AvacloudSDK import { AvaCloudSDK } from "@avalabs/avacloud-sdk"; const avaCloudSDK = new AvaCloudSDK({ apiKey: "", chainId: "53935", network: "mainnet", }); async function run() { const result = await avaCloudSDK.data.evm.transactions.listErc20Transactions({ pageSize: 10, address: "0x1137643FE14b032966a59Acd68EBf3c1271Df316", }); // Handle the result console.log(JSON.stringify(result, null, 2)); } run(); ``` ```bash cURL curl --request GET \ --url https://glacier-api.avax.network/v1/chains/43114/addresses/0x71C7656EC7ab88b098defB751B7401B5f6d8976F/transactions:listErc20 \ --header 'x-glacier-api-key: ' ``` Response ```json { "result": { "nextPageToken": "f8dba2d2-b128-41ae-be6b-5a6f76ca5141", "transactions": [ { "blockNumber": "36952303", "blockTimestamp": 1725460283, "blockHash": "0xb18c21736207b15efa0bdc1377c9ffde8c95bd20bd8b7422cc5eaefad41375a6", "txHash": "0x5d88c29e5d10d60a56f98d44883b6f8a82461dfe4c7b15e4c5726d626c41a484", "from": { "address": "0x1137643FE14b032966a59Acd68EBf3c1271Df316" }, "to": { "address": "0x6ef29103747EdFA66bcb3237D5AE4f773a5B9beE" }, "logIndex": 21, "value": "16800000000000000", "erc20Token": { "address": "0x04b9dA42306B023f3572e106B11D82aAd9D32EBb", "name": "Crystals", "symbol": "CRYSTAL", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/0212db53-26f6-4e56-99a2-05526ce32816/4a62bf9e90f401ea69fcf89496cbe96a/53935-0x04b9dA42306B023f3572e106B11D82aAd9D32EBb.png", "ercType": "ERC-20", "price": { "currencyCode": "usd", "value": 0.00719546 } } }, { "blockNumber": "36952300", "blockTimestamp": 1725460277, "blockHash": "0xf0c3017e0428ae2442fb0162d5ed0bd3c735ab25b5e85e94b0fe3cb97a914ede", "txHash": "0xea4aa8e2fa0b78aaf624252b762a32bcf5361ce441a7bc464edfd0bae3302a0e", "from": { "address": "0x3f04bAD8c90984e16e51656270f82D6C3B73a571" }, "to": { "address": "0x1137643FE14b032966a59Acd68EBf3c1271Df316" }, "logIndex": 83, "value": "1350000000000000000", "erc20Token": { "address": "0x04b9dA42306B023f3572e106B11D82aAd9D32EBb", "name": "Crystals", "symbol": "CRYSTAL", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/0212db53-26f6-4e56-99a2-05526ce32816/4a62bf9e90f401ea69fcf89496cbe96a/53935-0x04b9dA42306B023f3572e106B11D82aAd9D32EBb.png", "ercType": "ERC-20", "price": { "currencyCode": "usd", "value": 0.00719546 } } }, { "blockNumber": "36952297", "blockTimestamp": 1725460271, "blockHash": "0x1e9a118d60b931b7968c9bb5fbf615cecf14a1e0c15ab0ee4bdbca69150ef3f9", "txHash": "0x21fcc2430fe3d437bbb3147a877552a94a33bd02d29eb23731f26b80674fd78c", "from": { "address": "0x3f04bAD8c90984e16e51656270f82D6C3B73a571" }, "to": { "address": "0x1137643FE14b032966a59Acd68EBf3c1271Df316" }, "logIndex": 197, "value": "1350000000000000000", "erc20Token": { "address": "0x04b9dA42306B023f3572e106B11D82aAd9D32EBb", "name": "Crystals", "symbol": "CRYSTAL", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/0212db53-26f6-4e56-99a2-05526ce32816/4a62bf9e90f401ea69fcf89496cbe96a/53935-0x04b9dA42306B023f3572e106B11D82aAd9D32EBb.png", "ercType": "ERC-20", "price": { "currencyCode": "usd", "value": 0.00719546 } } }, { "blockNumber": "36952297", "blockTimestamp": 1725460271, "blockHash": "0x1e9a118d60b931b7968c9bb5fbf615cecf14a1e0c15ab0ee4bdbca69150ef3f9", "txHash": "0x5ec8a1e8ad42e2190633da46c69529ecf4d8c6c85d9df74db641e6f2a8a5e383", "from": { "address": "0x3f04bAD8c90984e16e51656270f82D6C3B73a571" }, "to": { "address": "0x1137643FE14b032966a59Acd68EBf3c1271Df316" }, "logIndex": 183, "value": "1350000000000000000", "erc20Token": { "address": "0x04b9dA42306B023f3572e106B11D82aAd9D32EBb", "name": "Crystals", "symbol": "CRYSTAL", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/0212db53-26f6-4e56-99a2-05526ce32816/4a62bf9e90f401ea69fcf89496cbe96a/53935-0x04b9dA42306B023f3572e106B11D82aAd9D32EBb.png", "ercType": "ERC-20", "price": { "currencyCode": "usd", "value": 0.00719546 } } }, { "blockNumber": "36952297", "blockTimestamp": 1725460271, "blockHash": "0x1e9a118d60b931b7968c9bb5fbf615cecf14a1e0c15ab0ee4bdbca69150ef3f9", "txHash": "0x643b4c239820667452fd5c38d2f1f980cbbb8ccd120682e76b21fcd742d43cb3", "from": { "address": "0x3f04bAD8c90984e16e51656270f82D6C3B73a571" }, "to": { "address": "0x1137643FE14b032966a59Acd68EBf3c1271Df316" }, "logIndex": 167, "value": "1350000000000000000", "erc20Token": { "address": "0x04b9dA42306B023f3572e106B11D82aAd9D32EBb", "name": "Crystals", "symbol": "CRYSTAL", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/0212db53-26f6-4e56-99a2-05526ce32816/4a62bf9e90f401ea69fcf89496cbe96a/53935-0x04b9dA42306B023f3572e106B11D82aAd9D32EBb.png", "ercType": "ERC-20", "price": { "currencyCode": "usd", "value": 0.00719546 } } }, { "blockNumber": "36952294", "blockTimestamp": 1725460263, "blockHash": "0xa15acd24ce980ce5ffcf12daf6ce538fd4f9896634b4a3f48c599c77192577cf", "txHash": "0x370627ddb71c638305a8cce92ecae69423115668039902f83aa4fd3a25983ee0", "from": { "address": "0x1137643FE14b032966a59Acd68EBf3c1271Df316" }, "to": { "address": "0x6ef29103747EdFA66bcb3237D5AE4f773a5B9beE" }, "logIndex": 246, "value": "18000000000000000", "erc20Token": { "address": "0x04b9dA42306B023f3572e106B11D82aAd9D32EBb", "name": "Crystals", "symbol": "CRYSTAL", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/0212db53-26f6-4e56-99a2-05526ce32816/4a62bf9e90f401ea69fcf89496cbe96a/53935-0x04b9dA42306B023f3572e106B11D82aAd9D32EBb.png", "ercType": "ERC-20", "price": { "currencyCode": "usd", "value": 0.00719546 } } }, { "blockNumber": "36952294", "blockTimestamp": 1725460263, "blockHash": "0xa15acd24ce980ce5ffcf12daf6ce538fd4f9896634b4a3f48c599c77192577cf", "txHash": "0xe8b58b9a413de06d4dbfebc226e3607f34a5071e7a0a315478a37d5ad76a7026", "from": { "address": "0xC475ecce788ECBF4b6E78BC501f4B1Ce73c46232" }, "to": { "address": "0x1137643FE14b032966a59Acd68EBf3c1271Df316" }, "logIndex": 38, "value": "300000000000000000", "erc20Token": { "address": "0x04b9dA42306B023f3572e106B11D82aAd9D32EBb", "name": "Crystals", "symbol": "CRYSTAL", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/0212db53-26f6-4e56-99a2-05526ce32816/4a62bf9e90f401ea69fcf89496cbe96a/53935-0x04b9dA42306B023f3572e106B11D82aAd9D32EBb.png", "ercType": "ERC-20", "price": { "currencyCode": "usd", "value": 0.00719546 } } }, { "blockNumber": "36952294", "blockTimestamp": 1725460263, "blockHash": "0xa15acd24ce980ce5ffcf12daf6ce538fd4f9896634b4a3f48c599c77192577cf", "txHash": "0xe8b58b9a413de06d4dbfebc226e3607f34a5071e7a0a315478a37d5ad76a7026", "from": { "address": "0xC475ecce788ECBF4b6E78BC501f4B1Ce73c46232" }, "to": { "address": "0x1137643FE14b032966a59Acd68EBf3c1271Df316" }, "logIndex": 22, "value": "300000000000000000", "erc20Token": { "address": "0x04b9dA42306B023f3572e106B11D82aAd9D32EBb", "name": "Crystals", "symbol": "CRYSTAL", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/0212db53-26f6-4e56-99a2-05526ce32816/4a62bf9e90f401ea69fcf89496cbe96a/53935-0x04b9dA42306B023f3572e106B11D82aAd9D32EBb.png", "ercType": "ERC-20", "price": { "currencyCode": "usd", "value": 0.00719546 } } }, { "blockNumber": "36952294", "blockTimestamp": 1725460263, "blockHash": "0xa15acd24ce980ce5ffcf12daf6ce538fd4f9896634b4a3f48c599c77192577cf", "txHash": "0xe8b58b9a413de06d4dbfebc226e3607f34a5071e7a0a315478a37d5ad76a7026", "from": { "address": "0xC475ecce788ECBF4b6E78BC501f4B1Ce73c46232" }, "to": { "address": "0x1137643FE14b032966a59Acd68EBf3c1271Df316" }, "logIndex": 6, "value": "300000000000000000", "erc20Token": { "address": "0x04b9dA42306B023f3572e106B11D82aAd9D32EBb", "name": "Crystals", "symbol": "CRYSTAL", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/0212db53-26f6-4e56-99a2-05526ce32816/4a62bf9e90f401ea69fcf89496cbe96a/53935-0x04b9dA42306B023f3572e106B11D82aAd9D32EBb.png", "ercType": "ERC-20", "price": { "currencyCode": "usd", "value": 0.00719546 } } }, { "blockNumber": "36952292", "blockTimestamp": 1725460259, "blockHash": "0x2b59f6314f27da325237afd457757cbd48302b7e292cc711f9b8d20cb5befea6", "txHash": "0xc6a98299de6cb14b8dccaeb9204fca3c93966f5a6da77d6dd799aa94e72f51ff", "from": { "address": "0x1137643FE14b032966a59Acd68EBf3c1271Df316" }, "to": { "address": "0x063DEB90452247AEcE9Be5F6c076446b3ca01910" }, "logIndex": 19, "value": "5000000000000000", "erc20Token": { "address": "0x04b9dA42306B023f3572e106B11D82aAd9D32EBb", "name": "Crystals", "symbol": "CRYSTAL", "decimals": 18, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/0212db53-26f6-4e56-99a2-05526ce32816/4a62bf9e90f401ea69fcf89496cbe96a/53935-0x04b9dA42306B023f3572e106B11D82aAd9D32EBb.png", "ercType": "ERC-20", "price": { "currencyCode": "usd", "value": 0.00719546 } } } ] } } ``` Congratulations 🎉 You’ve successfully retrieved the list of ERC-20 transfers for a wallet address with just a few lines of code using the Data API!​ # Etna Upgrade Source: https://developers.avacloud.io/data-api/etna The **Avalanche9000 (Etna Upgrade)** is focused on reinventing Subnets and providing other UX enhancements. One of the major changes in this upgrade is how users manage subnets and their validators. See [ACP 77](https://github.com/avalanche-foundation/ACPs/tree/main/ACPs/77-reinventing-subnets). ## Pre-Etna vs. Post-Etna ### Pre-Etna * A node had to be a **Primary Network Validator** before it could validate a Subnet. * All validators, delegators, and rewards for permissionless subnets were managed on the **P-Chain**. ### Post-Etna: The Avalanche network now supports both **Subnets** and **Layer 1 blockchains (L1s)**: * **Subnets (legacy flow):** * Do not pay a continuous fee. * Validators must be Primary Network Validators. * **L1s (new flow):** * Pay a continuous fee. * Validators do not need to be Primary Network Validators. * Can be either permissioned or permissionless, depending on the chain manager. This shift moves the responsibility of validator management from the P-Chain to the Subnets themselves. Permissionless Subnets have been rebranded as **L1s**, reflecting their true potential as independent Layer 1 blockchains. The P-Chain now handles only the registration of these L1 validators and imposes a subscription fee based on the number of active validators for each L1. Each L1 manages its validators through a [Validator Manager Smart Contract](https://github.com/ava-labs/teleporter/blob/main/contracts/validator-manager/README.md) deployed on a specific blockchain within that L1, streamlining operations and decentralizing management. *** ## Impact on existing subnets Existing subnets will continue to operate under the legacy flow unless they choose to convert to an L1 using the `ConvertSubnetToL1Tx` transaction. Validators of these Subnets must remain Primary Network Validators. There is no mandatory action required for existing Subnets; however, they can opt to leverage the new L1 functionalities if desired. *** ## L1 validator registration To convert a permissioned Subnet into an L1, you need to issue a `ConvertSubnetToL1Tx` transaction, providing the validator manager smart contract address and the blockchain ID where this contract is deployed. This transaction requires an array of initial L1 validators with the following details: * `nodeID`: NodeID of the validator being added. * `weight`: Weight of the validator being added. * `balance`: Initial balance for this validator. * `signer`: The BLS public key and proof-of-possession for the validator. * `disableOwner`: The P-Chain owner (a set of addresses and threshold) authorized to disable the validator using DisableL1ValidatorTx.. * `remainingBalanceOwner`: The P-Chain owner where any leftover AVAX from the validator’s balance will be sent when the validator is removed from the validator set. Additional L1 validators can be added later by issuing a `RegisterL1ValidatorTx` and providing the necessary validator details. These L1 validators are assigned a unique `validationID` to identify them across the network. The `validationID` remains valid from the registration of a `NodeID` on a Subnet until it is disabled by setting its weight to `0`. *** ## Weight and balance Weight and Balance of an L1 validator can be updated by issuing following transactions corresponding to their L1 `validationID`: * `SetL1ValidatorWeightTx` - Updates the weight of an L1 validator. If the weight is set to `0`, then the validator will be removed and the remaining balance will be returned to `RemainingBalanceOwner`. * `IncreaseL1ValidatorBalanceTx` - Increases the balance of an L1 validator which will be used as a maintenance fee to the Primary Network. * `DisableL1ValidatorTx` - Marks the validator as inactive and returning the remaining balance to the `RemainingBalanceOwner`. *** ## Continuous fee mechanism L1 validators are required to maintain a balance on the P-Chain to cover continuous fees for their participation in the network. The fee is deducted over time from the validator’s balance and is used to compensate for the resources consumed on the Primary Network. Validators should monitor their balance regularly and use the `IncreaseL1ValidatorBalanceTx` to top up their balance as needed to prevent becoming inactive. ### Fee calculation: * The continuous fee is calculated based on network parameters and the number of active L1 validators. * The minimum fee rate is **512 nAVAX per second**, which equates to approximately **1.33 AVAX per month** per validator when the number of validators is at or below the target. ### Recommendations for validators: * Set up alerts or monitoring tools to track balance levels. * Plan regular intervals for balance top-ups to ensure uninterrupted validation services. * Remember that any unspent balance can be reclaimed using the `DisableL1ValidatorTx`. *** ## Data API changes To incorporate Etna-related data, we have made the following changes to the Data API’s Primary Network endpoints: ### 1. List L1 validators **New endpoint:** [List L1 Validators](/data-api/primary-network/list-l1-validators) * **Purpose:** Allows listing all or specific L1 validators. * **Parameters or query changes:** * `L1ValidationID`: Get details of a specific L1 validator. * `SubnetID`: Filter validators of a particular subnet. * `NodeID`: Filter validators associated with a specific `NodeID`. * `IncludeInactiveL1Validators`: Include inactive L1 validators in the response. * **Response Changes:** * Returns a list of L1 validators. Refer to the [endpoint documentation](/data-api/primary-network/list-l1-validators) for full details. *** ### 2. List L1 validator transactions **Updated endpoint:** [List latest transactions on the primary network](/data-api/primary-network-transactions/list-latest-transactions) * **Changes:** * Added a new query parameter `L1ValidationID`. * **Purpose:** * By providing `L1ValidationID`, you receive all transactions linked to the validator’s `validationID`, such as `ConvertSubnetToL1Tx`, `IncreaseL1ValidatorBalanceTx`, or `DisableL1ValidatorTx`. * **Sorting and filtering:** * Transactions can only be sorted in descending order by their `timestamp`. * Additional filters include start and end timestamp bounds and transaction types (`txTypes`). * **Response changes:** * Refer to [New Transaction Properties](/data-api/etna#3-new-transaction-properties) for details. *** ### 3. New transaction properties **Updated endpoints:** * [Get Transaction](https://developers.avacloud.io/data-api/primary-network-transactions/get-transaction) * [List Latest Transactions](https://developers.avacloud.io/data-api/primary-network-transactions/list-latest-transactions) * [List Staking Transactions](https://developers.avacloud.io/data-api/primary-network-transactions/list-staking-transactions) **Parameters or query changes:** * None **Response changes:**
The `PChainTransaction` response type now includes the following new properties: * `L1ValidatorManagerDetails`: * `BlockchainID`: The blockchain ID where the validator manager is deployed. * `ContractAddress`: Address of the validator manager smart contract. * `L1ValidatorDetails` * `validationID`: Unique identifier for this L1 validation. * `nodeID`: NodeID of the validator. * `subnetID`: SubnetID of which this validationID belongs to. * `weight`: Weight to be used when participating in validation process. * `remainingBalance`: Remaining L1 validator balance in nAVAX until inactive. * `balanceChange`: Change in Balance of validator in the current transaction. * `AmountL1ValidatorBalanceBurned` * Asset details and amount of AVAX burned to increase the L1 validator balance *** ### 4. New block properties **Updated endpoints:** * [Get Block](https://developers.avacloud.io/data-api/primary-network-blocks/get-block) * [List Latest Blocks](https://developers.avacloud.io/data-api/primary-network-blocks/list-latest-blocks) * [List Blocks Proposed By Node](https://developers.avacloud.io/data-api/primary-network-blocks/list-blocks-proposed-by-node) **Parameters or query changes:** * None **Response changes:**
Each P-Chain block will now include properties representing L1 validators state at that block height: * `ActiveL1Validators`: Total active L1 validators * `L1ValidatorsAccruedFees`: Total fees accrued by network (in nAVAX) from active L1 validators *** ### 5. New Subnet Properties **Updated endpoint:** * [Get Subnet Details By ID](https://developers.avacloud.io/data-api/primary-network/get-subnet-details-by-id) * [List Subnets](https://developers.avacloud.io/data-api/primary-network/list-subnets) **Parameters or query changes:** * None **Response changes:**
Each Subnet will now have a new property IsL1 to identify whether it has been converted to an L1 or not. For all L1s, there will be a new property: * `isL1`: Whether the subnet is converted to L1 or not * `L1ValidatorManagerDetails`: Includes `blockchainID` and contract address of the validator manager. ## Additional Resources For more detailed information and technical specifications, please refer to the following resources: * [**ACP-77: Reinventing Subnets**:](https://github.com/avalanche-foundation/ACPs/tree/main/ACPs/77-reinventing-subnets) ACP 77 provides an in-depth explanation of the changes introduced in the Etna Upgrade. * [**What to Expect After the Etna Upgrade**:](https://academy.avax.network/guide/etna-changes) This guide outlines the operational impact on existing network participants expected from the activation of the AvalancheGo "Etna" upgrade. * [**Subnet & L1 Validators, What's the Difference?**:](https://academy.avax.network/guide/subnet-vs-l1-validators) This guide defines the difference between Subnet and L1 validators, differentiating the roles and responsibilities of each. * [**Validator Manager Smart Contract Documentation**:](https://github.com/ava-labs/teleporter/blob/main/contracts/validator-manager/README.md) Validator Manager Smart Contract contains technical details on deploying and interacting with the validator manager. * [**AvalancheGo Implementation Details**:](https://github.com/ava-labs/avalanchego/releases/tag/v1.12.0-fuji) For developers interested in the implementation, refer to the AvalancheGo repository. * [**Etna DevNet Resources**:](https://github.com/ava-labs/etna-devnet-resources) The Etna DevNet is a temporary Avalanche network instance that was created for the purpose of testing and integrating with the changes introduced in the Etna upgrade prior to their activation on the Fuji testnet. The Etna Upgrade marks a significant milestone in the evolution of the Avalanche network, introducing more flexibility and autonomy for Subnets through the concept of Layer 1 blockchains. By understanding and leveraging these new features, network participants can optimize their operations and contribute to the growth and decentralization of the Avalanche ecosystem. # Get native token balance Source: https://developers.avacloud.io/data-api/evm-balances/get-native-token-balance get /v1/chains/{chainId}/addresses/{address}/balances:getNative Gets native token balance of a wallet address. Balance at a given block can be retrieved with the `blockNumber` parameter. # List collectible (ERC-721/ERC-1155) balances Source: https://developers.avacloud.io/data-api/evm-balances/list-collectible-erc-721erc-1155-balances get /v1/chains/{chainId}/addresses/{address}/balances:listCollectibles Lists ERC-721 and ERC-1155 token balances of a wallet address. Balance for a specific contract can be retrieved with the `contractAddress` parameter. # List ERC-1155 balances Source: https://developers.avacloud.io/data-api/evm-balances/list-erc-1155-balances get /v1/chains/{chainId}/addresses/{address}/balances:listErc1155 Lists ERC-1155 token balances of a wallet address. Balance at a given block can be retrieved with the `blockNumber` parameter. Balance for a specific contract can be retrieved with the `contractAddress` parameter. # List ERC-20 balances Source: https://developers.avacloud.io/data-api/evm-balances/list-erc-20-balances get /v1/chains/{chainId}/addresses/{address}/balances:listErc20 Lists ERC-20 token balances of a wallet address. Balance at a given block can be retrieved with the `blockNumber` parameter. Balance for specific contracts can be retrieved with the `contractAddresses` parameter. # List ERC-721 balances Source: https://developers.avacloud.io/data-api/evm-balances/list-erc-721-balances get /v1/chains/{chainId}/addresses/{address}/balances:listErc721 Lists ERC-721 token balances of a wallet address. Balance for a specific contract can be retrieved with the `contractAddress` parameter. # Get block Source: https://developers.avacloud.io/data-api/evm-blocks/get-block get /v1/chains/{chainId}/blocks/{blockId} Gets the details of an individual block on the EVM-compatible chain. # List latest blocks Source: https://developers.avacloud.io/data-api/evm-blocks/list-latest-blocks get /v1/chains/{chainId}/blocks Lists the latest indexed blocks on the EVM-compatible chain sorted in descending order by block timestamp. # List latest blocks across all supported EVM chains Source: https://developers.avacloud.io/data-api/evm-blocks/list-latest-blocks-across-all-supported-evm-chains get /v1/blocks Lists the most recent blocks from all supported EVM-compatible chains. The results can be filtered by network. # Get chain information Source: https://developers.avacloud.io/data-api/evm-chains/get-chain-information get /v1/chains/{chainId} Gets chain information for the EVM-compatible chain if supported by AvaCloud. # null Source: https://developers.avacloud.io/data-api/evm-chains/get-chains-for-address get /v1/chains/address/{address} **[Deprecated]** Gets a list of all chains where the address was either a sender or receiver in a transaction or ERC transfer. The list is currently updated every 15 minutes. ⚠️ **This operation will be removed in a future release. Please use /v1/address/:address/chains endpoint instead** . # List all chains associated with a given address Source: https://developers.avacloud.io/data-api/evm-chains/list-all-chains-associated-with-a-given-address get /v1/address/{address}/chains Lists the chains where the specified address has participated in transactions or ERC token transfers, either as a sender or receiver. The data is refreshed every 15 minutes. # List chains Source: https://developers.avacloud.io/data-api/evm-chains/list-chains get /v1/chains Lists the AvaCloud supported EVM-compatible chains. Filterable by network. # null Source: https://developers.avacloud.io/data-api/evm-chains/list-latest-blocks-for-all-supported-evm-chains get /v1/chains/allBlocks **[Deprecated]** Lists the latest blocks for all supported EVM chains. Filterable by network. ⚠️ **This operation will be removed in a future release. Please use /v1/blocks endpoint instead** . # null Source: https://developers.avacloud.io/data-api/evm-chains/list-latest-transactions-for-all-supported-evm-chains get /v1/chains/allTransactions **[Deprecated]** Lists the latest transactions for all supported EVM chains. Filterable by status. ⚠️ **This operation will be removed in a future release. Please use /v1/transactions endpoint instead** . # Get contract metadata Source: https://developers.avacloud.io/data-api/evm-contracts/get-contract-metadata get /v1/chains/{chainId}/addresses/{address} Gets metadata about the contract at the given address. # Get deployment transaction Source: https://developers.avacloud.io/data-api/evm-transactions/get-deployment-transaction get /v1/chains/{chainId}/contracts/{address}/transactions:getDeployment If the address is a smart contract, returns the transaction in which it was deployed. # Get transaction Source: https://developers.avacloud.io/data-api/evm-transactions/get-transaction get /v1/chains/{chainId}/transactions/{txHash} Gets the details of a single transaction. # List deployed contracts Source: https://developers.avacloud.io/data-api/evm-transactions/list-deployed-contracts get /v1/chains/{chainId}/contracts/{address}/deployments Lists all contracts deployed by the given address. # List ERC-1155 transfers Source: https://developers.avacloud.io/data-api/evm-transactions/list-erc-1155-transfers get /v1/chains/{chainId}/addresses/{address}/transactions:listErc1155 Lists ERC-1155 transfers for an address. Filterable by block range. # List ERC-20 transfers Source: https://developers.avacloud.io/data-api/evm-transactions/list-erc-20-transfers get /v1/chains/{chainId}/addresses/{address}/transactions:listErc20 Lists ERC-20 transfers for an address. Filterable by block range. # List ERC-721 transfers Source: https://developers.avacloud.io/data-api/evm-transactions/list-erc-721-transfers get /v1/chains/{chainId}/addresses/{address}/transactions:listErc721 Lists ERC-721 transfers for an address. Filterable by block range. # List ERC transfers Source: https://developers.avacloud.io/data-api/evm-transactions/list-erc-transfers get /v1/chains/{chainId}/tokens/{address}/transfers Lists ERC transfers for an ERC-20, ERC-721, or ERC-1155 contract address. # List internal transactions Source: https://developers.avacloud.io/data-api/evm-transactions/list-internal-transactions get /v1/chains/{chainId}/addresses/{address}/transactions:listInternals Returns a list of internal transactions for an address and chain. Filterable by block range. Note that the internal transactions list only contains `CALL` or `CALLCODE` transactions with a non-zero value and `CREATE`/`CREATE2`/`CREATE3` transactions. To get a complete list of internal transactions use the `debug_` prefixed RPC methods on an archive node. # List latest transactions Source: https://developers.avacloud.io/data-api/evm-transactions/list-latest-transactions get /v1/chains/{chainId}/transactions Lists the latest transactions. Filterable by status. # List native transactions Source: https://developers.avacloud.io/data-api/evm-transactions/list-native-transactions get /v1/chains/{chainId}/addresses/{address}/transactions:listNative Lists native transactions for an address. Filterable by block range. # List the latest transactions across all supported EVM chains Source: https://developers.avacloud.io/data-api/evm-transactions/list-the-latest-transactions-across-all-supported-evm-chains get /v1/transactions Lists the most recent transactions from all supported EVM-compatible chains. The results can be filtered based on transaction status. # List transactions Source: https://developers.avacloud.io/data-api/evm-transactions/list-transactions get /v1/chains/{chainId}/addresses/{address}/transactions Returns a list of transactions where the given wallet address had an on-chain interaction for the given chain. The ERC-20 transfers, ERC-721 transfers, ERC-1155, and internal transactions returned are only those where the input address had an interaction. Specifically, those lists only inlcude entries where the input address was the sender (`from` field) or the receiver (`to` field) for the sub-transaction. Therefore the transactions returned from this list may not be complete representations of the on-chain data. For a complete view of a transaction use the `/chains/:chainId/transactions/:txHash` endpoint. Filterable by block ranges. # List transactions for a block Source: https://developers.avacloud.io/data-api/evm-transactions/list-transactions-for-a-block get /v1/chains/{chainId}/blocks/{blockId}/transactions Lists the transactions that occured in a given block. # Getting Started Source: https://developers.avacloud.io/data-api/getting-started To begin, create your free AvaCloud account by visiting [AvaCloud](https://app.avacloud.io/). Once the account is created: 1. Navigating to **Web3 Data API** 2. Click on **Add API Key** 3. Set an alias and click on **create** 4. Copy the the value Always keep your API keys in a secure environment. Never expose them in public repositories, such as GitHub, or share them with unauthorized individuals. Compromised API keys can lead to unauthorized access and potential misuse of your account. With your API Key you can start making queries, for example to get the latest block on the C-chain(43114): ```bash curl --location 'https://glacier-api.avax.network/v1/chains/43114/blocks' \ --header 'accept: application/json' \ --header 'x-glacier-api-key: ' \ ``` And you should see something like this: ```json { "blocks": [ { "blockNumber": "49889407", "blockTimestamp": 1724990250, "blockHash": "0xd34becc82943e3e49048cdd3f75b80a87e44eb3aed6b87cc06867a7c3b9ee213", "txCount": 1, "baseFee": "25000000000", "gasUsed": "53608", "gasLimit": "15000000", "gasCost": "0", "parentHash": "0xf4917efb4628a1d8f4d101b3d15bce9826e62ef2c93c3e16ee898d27cf02f3d4", "feesSpent": "1435117553916960", "cumulativeTransactions": "500325352" }, { "blockNumber": "49889406", "blockTimestamp": 1724990248, "blockHash": "0xf4917efb4628a1d8f4d101b3d15bce9826e62ef2c93c3e16ee898d27cf02f3d4", "txCount": 2, "baseFee": "25000000000", "gasUsed": "169050", "gasLimit": "15000000", "gasCost": "0", "parentHash": "0x2a54f142fa3acee92a839b071bb6c7cca7abc2a797cf4aac68b07f79406ac0cb", "feesSpent": "4226250000000000", "cumulativeTransactions": "500325351" }, { "blockNumber": "49889405", "blockTimestamp": 1724990246, "blockHash": "0x2a54f142fa3acee92a839b071bb6c7cca7abc2a797cf4aac68b07f79406ac0cb", "txCount": 4, "baseFee": "25000000000", "gasUsed": "618638", "gasLimit": "15000000", "gasCost": "0", "parentHash": "0x0cda1bb5c86e790976c9330c9fc26e241a705afbad11a4caa44df1c81058451d", "feesSpent": "16763932426044724", "cumulativeTransactions": "500325349" }, { "blockNumber": "49889404", "blockTimestamp": 1724990244, "blockHash": "0x0cda1bb5c86e790976c9330c9fc26e241a705afbad11a4caa44df1c81058451d", "txCount": 3, "baseFee": "25000000000", "gasUsed": "254544", "gasLimit": "15000000", "gasCost": "0", "parentHash": "0x60e55dd9eacc095c07f50a73e02d81341c406584f7abbf5d10d938776a4c893c", "feesSpent": "6984642298020000", "cumulativeTransactions": "500325345" }, { "blockNumber": "49889403", "blockTimestamp": 1724990242, "blockHash": "0x60e55dd9eacc095c07f50a73e02d81341c406584f7abbf5d10d938776a4c893c", "txCount": 2, "baseFee": "25000000000", "gasUsed": "65050", "gasLimit": "15000000", "gasCost": "0", "parentHash": "0xa3e9f91f45a85ed00b8ebe8e5e976ed1a1f52612143eddd3de9d2588d05398b8", "feesSpent": "1846500000000000", "cumulativeTransactions": "500325342" }, { "blockNumber": "49889402", "blockTimestamp": 1724990240, "blockHash": "0xa3e9f91f45a85ed00b8ebe8e5e976ed1a1f52612143eddd3de9d2588d05398b8", "txCount": 2, "baseFee": "25000000000", "gasUsed": "74608", "gasLimit": "15000000", "gasCost": "0", "parentHash": "0x670db772edfc2fdae322d55473ba0670690aed6358a067a718492c819d63356a", "feesSpent": "1997299851936960", "cumulativeTransactions": "500325340" }, { "blockNumber": "49889401", "blockTimestamp": 1724990238, "blockHash": "0x670db772edfc2fdae322d55473ba0670690aed6358a067a718492c819d63356a", "txCount": 1, "baseFee": "25000000000", "gasUsed": "273992", "gasLimit": "15000000", "gasCost": "0", "parentHash": "0x75742cf45383ce54823690b9dd2e85a743be819281468163d276f145d077902a", "feesSpent": "7334926295195040", "cumulativeTransactions": "500325338" }, { "blockNumber": "49889400", "blockTimestamp": 1724990236, "blockHash": "0x75742cf45383ce54823690b9dd2e85a743be819281468163d276f145d077902a", "txCount": 1, "baseFee": "25000000000", "gasUsed": "291509", "gasLimit": "15000000", "gasCost": "0", "parentHash": "0xe5055eae3e1fd2df24b61e9c691f756c97e5619cfc66b69cbcb6025117d1bde7", "feesSpent": "7724988500000000", "cumulativeTransactions": "500325337" }, { "blockNumber": "49889399", "blockTimestamp": 1724990234, "blockHash": "0xe5055eae3e1fd2df24b61e9c691f756c97e5619cfc66b69cbcb6025117d1bde7", "txCount": 8, "baseFee": "25000000000", "gasUsed": "824335", "gasLimit": "15000000", "gasCost": "0", "parentHash": "0xbcacff928f7dd20cc1522155e7c9b9716997914b53ab94034b813c3f207174ef", "feesSpent": "21983004380692400", "cumulativeTransactions": "500325336" }, { "blockNumber": "49889398", "blockTimestamp": 1724990229, "blockHash": "0xbcacff928f7dd20cc1522155e7c9b9716997914b53ab94034b813c3f207174ef", "txCount": 1, "baseFee": "25000000000", "gasUsed": "21000", "gasLimit": "15000000", "gasCost": "0", "parentHash": "0x0b686812078429d33e4224d2b48bd26b920db8dbb464e7f135d980759ca7e947", "feesSpent": "562182298020000", "cumulativeTransactions": "500325328" } ], "nextPageToken": "9f9e1d25-14a9-49f4-8742-fd4bf12f7cd8" } ``` Congratulations! You’ve successfully set up your account and made your first query to the Data API 🚀🚀🚀 # Get the health of the service Source: https://developers.avacloud.io/data-api/health-check/get-the-health-of-the-service get /v1/health-check Check the health of the service. # Get an ICM message Source: https://developers.avacloud.io/data-api/interchain-messaging/get-an-icm-message get /v1/icm/messages/{messageId} Gets an ICM message by teleporter message ID. # List ICM messages Source: https://developers.avacloud.io/data-api/interchain-messaging/list-icm-messages get /v1/icm/messages Lists ICM messages. Ordered by timestamp in descending order. # List ICM messages by address Source: https://developers.avacloud.io/data-api/interchain-messaging/list-icm-messages-by-address get /v1/icm/addresses/{address}/messages Lists ICM messages by address. Ordered by timestamp in descending order. # How to get the native balance of an address Source: https://developers.avacloud.io/data-api/native-balance Checking the balance of a wallet is vital for users who want to manage their digital assets effectively. By reviewing their wallet balance, users can: * **Track their asset portfolio**: Regularly monitoring the wallet balance keeps users informed about the value of their holdings, enabling them to make informed decisions on buying, selling, or retaining their digital assets. * **Confirm received transactions**: When expecting digital assets, verifying the wallet balance helps ensure that transactions have been successfully completed and the correct amounts have been received. * **Plan future transactions**: Knowing the wallet’s balance allows users to prepare for upcoming transactions and verify that they have enough funds to cover fees or other related costs. This guide will walk you through how to get the native balance associated with a specific wallet address on the C-chain network using the Data API. ### Step 1: Set Up AvaCloud First, ensure that you have set up [AvaCloud](https://app.avacloud.io/) and have access to your API key. If you’re new to Avacloud, create an account and obtain an API key. ### Step 2: Retrieve the Native Balance of an Address To obtain the native balance of a wallet address you can use [Get native token balance](/data-api/evm-balances/get-native-token-balance) endpoint. You’ll need to specify the `chainId` and the `address` for which you want to retrieve the balance. Here’s how you can do it: ```javascript AvacloudSDK import { AvaCloudSDK } from "@avalabs/avacloud-sdk"; const avaCloudSDK = new AvaCloudSDK({ apiKey: "", chainId: "43114", network: "mainnet", }); async function run() { const result = await avaCloudSDK.data.evm.balances.getNativeBalance({ blockNumber: "6479329", address: "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", currency: "usd", }); // Handle the result console.log(JSON.stringify(result, null, 2)); } run(); ``` ```bash cURL curl --request GET \ --url https://glacier-api.avax.network/v1/chains/43114/addresses/0x71C7656EC7ab88b098defB751B7401B5f6d8976F/balances:getNative \ --header 'x-glacier-api-key: ' ``` Response ```json { "nativeTokenBalance": { "chainId": "43114", "name": "Avalanche", "symbol": "AVAX", "decimals": 18, "price": { "currencyCode": "usd", "value": 26.32 }, "balance": "3316667947990566036", "balanceValue": { "currencyCode": "usd", "value": 87.29 }, "logoUri": "https://images.ctfassets.net/gcj8jwzm6086/5VHupNKwnDYJvqMENeV7iJ/3e4b8ff10b69bfa31e70080a4b142cd0/avalanche-avax-logo.svg" } } ``` Congratulations 🎉 You’ve successfully retrieved the native balance of a wallet address using just a few lines of code with the Data API! # Get token details Source: https://developers.avacloud.io/data-api/nfts/get-token-details get /v1/chains/{chainId}/nfts/collections/{address}/tokens/{tokenId} Gets token details for a specific token of an NFT contract. # List tokens Source: https://developers.avacloud.io/data-api/nfts/list-tokens get /v1/chains/{chainId}/nfts/collections/{address}/tokens Lists tokens for an NFT contract. # Reindex NFT metadata Source: https://developers.avacloud.io/data-api/nfts/reindex-nft-metadata post /v1/chains/{chainId}/nfts/collections/{address}/tokens/{tokenId}:reindex Triggers reindexing of token metadata for an NFT token. Reindexing can only be called once per hour for each NFT token. # Create transaction export operation Source: https://developers.avacloud.io/data-api/operations/create-transaction-export-operation post /v1/operations/transactions:export Trigger a transaction export operation with given parameters. The transaction export operation runs asynchronously in the background. The status of the job can be retrieved from the `/v1/operations/:operationId` endpoint using the `operationId` returned from this endpoint. # Get operation Source: https://developers.avacloud.io/data-api/operations/get-operation get /v1/operations/{operationId} Gets operation details for the given operation id. # Overview Source: https://developers.avacloud.io/data-api/overview ### What is the Data API? The Data API provides web3 application developers with multi-chain data related to Avalanche's primary network, Avalanche L1s, and Ethereum. With the Data API, you can easily build products that leverage real-time and historical transaction and transfer history, native and token balances, and various types of token metadata. ![Data API](https://mintlify.s3.us-west-1.amazonaws.com/avalabs-47ea3976/images/data-api.png) The [Data API](/data-api), along with the [Metrics API](/metrics-api), are the engines behind the [Avalanche Explorer](https://subnets.avax.network/stats/) and the [Core wallet](https://core.app/en/). They are used to display transactions, logs, balances, NFTs, and more. The data and visualizations presented are all powered by these APIs, offering real-time and historical insights that are essential for building sophisticated, data-driven blockchain products. The Data API and Glacier API refer to the same API. If you encounter the term “Glacier API” in other documentation, it is referring to the Data API, which was previously known as the Glacier API.​ ### Features * **Extensive L1 Support**: Gain access to data from over 100+ L1s across both mainnet and testnet. If an L1 is listed on the [Avalanche Explorer](https://subnets.avax.network/), you can query its data using the Data API. * **Transactions and UTXOs**: easily retrieve details related to transactions, UTXOs, and token transfers from Avalanche EVMs, Ethereum, and Avalanche's Primary Network - the P-Chain, X-Chain and C-Chain. * **Blocks**: retrieve latest blocks and block details * **Balances**: fetch balances of native, ERC-20, ERC-721, and ERC-1155 tokens along with relevant metadata. * **Tokens**: augment your user experience with asset details. * **Staking**: get staking related data for active and historical validations. ### Supported Chains Avalanche’s architecture supports a diverse ecosystem of interconnected L1 blockchains, each operating independently while retaining the ability to seamlessly communicate with other L1s within the network. Central to this architecture is the Primary Network—Avalanche’s foundational network layer, which all validators are required to validate prior to [ACP-77](https://github.com/avalanche-foundation/ACPs/blob/main/ACPs/77-reinventing-subnets/README.md). The Primary Network runs three essential blockchains: * The Contract Chain (C-Chain) * The Platform Chain (P-Chain) * The Exchange Chain (X-Chain) However, with the implementation of [ACP-77](https://github.com/avalanche-foundation/ACPs/blob/main/ACPs/77-reinventing-subnets/README.md), this requirement will change. Subnet Validators will be able to operate independently of the Primary Network, allowing for more flexible and affordable Subnet creation and management. The **Data API** supports a wide range of L1 blockchains (**over 100**) across both **mainnet** and **testnet**, including popular ones like Beam, DFK, Lamina1, Dexalot, Shrapnel, and Pulsar. In fact, every L1 you see on the [Avalanche Explorer](https://subnets.avax.network/) can be queried through the Data API. This list is continually expanding as we keep adding more L1s. For a full list of supported chains, visit [List chains](/data-api/evm-chains/list-chains). #### The Contract Chain (C-Chain) The C-Chain is an implementation of the Ethereum Virtual Machine (EVM). The primary network endpoints only provide information related to C-Chain atomic memory balances and import/export transactions. For additional data, please reference the EVM APIs. #### The Platform Chain (P-Chain) The P-Chain is responsible for all validator and L1-level operations. The P-Chain supports the creation of new blockchains and L1s, the addition of validators to L1s, staking operations, and other platform-level operations. #### The Exchange Chain (X-Chain) The X-Chain is responsible for operations on digital smart assets known as Avalanche Native Tokens. A smart asset is a representation of a real-world resource (for example, equity, or a bond) with sets of rules that govern its behavior, like "can’t be traded until tomorrow." The X-Chain supports the creation and trade of Avalanche Native Tokens. | Feature | Description | | :--------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Chains** | Utilize this endpoint to retrieve the Primary Network chains that an address has transaction history associated with. | | **Blocks** | Blocks are the container for transactions executed on the Primary Network. Retrieve the latest blocks, a specific block by height or hash, or a list of blocks proposed by a specified NodeID on Primary Network chains. | | **Vertices** | Prior to Avalanche Cortina (v1.10.0), the X-Chain functioned as a DAG with vertices rather than blocks. These endpoints allow developers to retrieve historical data related to that period of chain history. Retrieve the latest vertices, a specific vertex, or a list of vertices at a specific height from the X-Chain. | | **Transactions** | Transactions are a user's primary form of interaction with a chain and provide details around their on-chain activity, including staking-related behavior. Retrieve a list of the latest transactions, a specific transaction, a list of active staking transactions for a specified address, or a list of transactions associated with a provided asset id from Primary Network chains. | | **UTXOs** | UTXOs are fundamental elements that denote the funds a user has available. Get a list of UTXOs for provided addresses from the Primary Network chains. | | **Balances** | User balances are an essential function of the blockchain. Retrieve balances related to the X and P-Chains, as well as atomic memory balances for the C-Chain. | | **Rewards** | Staking is the process where users lock up their tokens to support a blockchain network and, in return, receive rewards. It is an essential part of proof-of-stake (PoS) consensus mechanisms used by many blockchain networks, including Avalanche. Using the Data API, you can easily access pending and historical rewards associated with a set of addresses. | | **Assets** | Get asset details corresponding to the given asset id on the X-Chain. | #### EVM The C-Chain is an instance of the Coreth Virtual Machine, and many Avalanche L1s are instances of the *Subnet-EVM*, which is a Virtual Machine (VM) that defines the L1 Contract Chains. *Subnet-EVM* is a simplified version of *Coreth VM* (C-Chain). | Feature | Description | | :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Chains** | There are a number of chains supported by the Data API. These endpoints can be used to understand which chains are included/indexed as part of the API and retrieve information related to a specific chain. | | **Blocks** | Blocks are the container for transactions executed within the EVM. Retrieve the latest blocks or a specific block by height or hash. | | **Transactions** | Transactions are a user's primary form of interaction with a chain and provide details around their on-chain activity. These endpoints can be used to retrieve information related to specific transaction details, internal transactions, contract deployments, specific token standard transfers, and more! | | **Balances** | User balances are an essential function of the blockchain. Easily retrieve native token, collectible, and fungible token balances related to an EVM chain with these endpoints. | #### Operations The Operations API allows users to easily access their on-chain history by creating transaction exports returned in a CSV format. This API supports EVMs as well as non-EVM Primary Network chains. # Get balances Source: https://developers.avacloud.io/data-api/primary-network-balances/get-balances get /v1/networks/{network}/blockchains/{blockchainId}/balances Gets primary network balances for one of the Primary Network chains for the supplied addresses. C-Chain balances returned are only the shared atomic memory balance. For EVM balance, use the `/v1/chains/:chainId/addresses/:addressId/balances:getNative` endpoint. # Get block Source: https://developers.avacloud.io/data-api/primary-network-blocks/get-block get /v1/networks/{network}/blockchains/{blockchainId}/blocks/{blockId} Gets a block by block height or block hash on one of the Primary Network chains. # List blocks proposed by node Source: https://developers.avacloud.io/data-api/primary-network-blocks/list-blocks-proposed-by-node get /v1/networks/{network}/blockchains/{blockchainId}/nodes/{nodeId}/blocks Lists the latest blocks proposed by a given NodeID on one of the Primary Network chains. # List latest blocks Source: https://developers.avacloud.io/data-api/primary-network-blocks/list-latest-blocks get /v1/networks/{network}/blockchains/{blockchainId}/blocks Lists latest blocks on one of the Primary Network chains. # List historical rewards Source: https://developers.avacloud.io/data-api/primary-network-rewards/list-historical-rewards get /v1/networks/{network}/rewards Lists historical rewards on the Primary Network for the supplied addresses. # List pending rewards Source: https://developers.avacloud.io/data-api/primary-network-rewards/list-pending-rewards get /v1/networks/{network}/rewards:listPending Lists pending rewards on the Primary Network for the supplied addresses. # Get transaction Source: https://developers.avacloud.io/data-api/primary-network-transactions/get-transaction get /v1/networks/{network}/blockchains/{blockchainId}/transactions/{txHash} Gets the details of a single transaction on one of the Primary Network chains. # List asset transactions Source: https://developers.avacloud.io/data-api/primary-network-transactions/list-asset-transactions get /v1/networks/{network}/blockchains/{blockchainId}/assets/{assetId}/transactions Lists asset transactions corresponding to the given asset id on the X-Chain. # List latest transactions Source: https://developers.avacloud.io/data-api/primary-network-transactions/list-latest-transactions get /v1/networks/{network}/blockchains/{blockchainId}/transactions Lists the latest transactions on one of the Primary Network chains. Transactions are filterable by addresses, txTypes, and timestamps. When querying for latest transactions without an address parameter, filtering by txTypes and timestamps is not supported. An address filter must be provided to utilize txTypes and timestamp filters. For P-Chain, you can fetch all L1 validators related transactions like ConvertSubnetToL1Tx, IncreaseL1ValidatorBalanceTx etc. using the unique L1 validation ID. These transactions are further filterable by txTypes and timestamps as well. Given that each transaction may return a large number of UTXO objects, bounded only by the maximum transaction size, the query may return less transactions than the provided page size. The result will contain less results than the page size if the number of utxos contained in the resulting transactions reach a performance threshold. # List staking transactions Source: https://developers.avacloud.io/data-api/primary-network-transactions/list-staking-transactions get /v1/networks/{network}/blockchains/{blockchainId}/transactions:listStaking Lists active staking transactions on the P-Chain for the supplied addresses. # List UTXOs Source: https://developers.avacloud.io/data-api/primary-network-utxos/list-utxos get /v1/networks/{network}/blockchains/{blockchainId}/utxos Lists UTXOs on one of the Primary Network chains for the supplied addresses. # Get vertex Source: https://developers.avacloud.io/data-api/primary-network-vertices/get-vertex get /v1/networks/{network}/blockchains/{blockchainId}/vertices/{vertexHash} Gets a single vertex on the X-Chain. # List vertices Source: https://developers.avacloud.io/data-api/primary-network-vertices/list-vertices get /v1/networks/{network}/blockchains/{blockchainId}/vertices Lists latest vertices on the X-Chain. # List vertices by height Source: https://developers.avacloud.io/data-api/primary-network-vertices/list-vertices-by-height get /v1/networks/{network}/blockchains/{blockchainId}/vertices:listByHeight Lists vertices at the given vertex height on the X-Chain. # Get asset details Source: https://developers.avacloud.io/data-api/primary-network/get-asset-details get /v1/networks/{network}/blockchains/{blockchainId}/assets/{assetId} Gets asset details corresponding to the given asset id on the X-Chain. # Get blockchain details by ID Source: https://developers.avacloud.io/data-api/primary-network/get-blockchain-details-by-id get /v1/networks/{network}/blockchains/{blockchainId} Get details of the blockchain registered on the network. # Get chain interactions for addresses Source: https://developers.avacloud.io/data-api/primary-network/get-chain-interactions-for-addresses get /v1/networks/{network}/addresses:listChainIds Returns Primary Network chains that each address has touched in the form of an address mapped array. If an address has had any on-chain interaction for a chain, that chain's chain id will be returned. # Get network details Source: https://developers.avacloud.io/data-api/primary-network/get-network-details get /v1/networks/{network} Gets network details such as validator and delegator stats. # Get single validator details Source: https://developers.avacloud.io/data-api/primary-network/get-single-validator-details get /v1/networks/{network}/validators/{nodeId} List validator details for a single validator. Filterable by validation status. # Get Subnet details by ID Source: https://developers.avacloud.io/data-api/primary-network/get-subnet-details-by-id get /v1/networks/{network}/subnets/{subnetId} Get details of the Subnet registered on the network. # List blockchains Source: https://developers.avacloud.io/data-api/primary-network/list-blockchains get /v1/networks/{network}/blockchains Lists all blockchains registered on the network. # List delegators Source: https://developers.avacloud.io/data-api/primary-network/list-delegators get /v1/networks/{network}/delegators Lists details for delegators. # List L1 validators Source: https://developers.avacloud.io/data-api/primary-network/list-l1-validators get /v1/networks/{network}/l1Validators Lists details for L1 validators. By default, returns details for all active L1 validators. Filterable by validator node ids, subnet id, and validation id. # List subnets Source: https://developers.avacloud.io/data-api/primary-network/list-subnets get /v1/networks/{network}/subnets Lists all subnets registered on the network. # List validators Source: https://developers.avacloud.io/data-api/primary-network/list-validators get /v1/networks/{network}/validators Lists details for validators. By default, returns details for all validators. The nodeIds parameter supports substring matching. Filterable by validation status, delegation capacity, time remaining, fee percentage, uptime performance, and subnet id. # Rate Limits Source: https://developers.avacloud.io/data-api/rate-limits Rate limiting is managed through a weighted scoring system, known as Compute Units (CUs). Each API request consumes a specified number of CUs, determined by the complexity of the request. This system is designed to accommodate basic requests while efficiently handling more computationally intensive operations. ## Rate Limit Tiers The maximum CUs (rate-limiting score) for a user depends on their subscription level and is delineated in the following table: | Subscription Level | Per Minute Limit (CUs) | Per Day Limit (CUs) | | :----------------- | :--------------------- | :------------------ | | Unauthenticated | 6,000 | 1,200,000 | | Free | 8,000 | 2,000,000 | | Base | 10,000 | 3,750,000 | | Growth | 14,000 | 11,200,000 | | Pro | 20,000 | 25,000,000 | To update your subscription level use the [AvaCloud Portal](https://app.avacloud.io/) Note: Rate limits apply collectively across both Webhooks and Data APIs, with usage from each counting toward your total CU limit. ## Rate Limit Categories The CUs for each category are defined in the following table: {/* data weights value table start */} | Weight | CU Value | | :----- | :------- | | Free | 1 | | Small | 10 | | Medium | 20 | | Large | 50 | | XL | 100 | | XXL | 200 | {/* data weights value table end */} ## Rate Limits for Data API Endpoints The CUs for each route are defined in the table below: {/* data execution weights table start */} | Endpoint | Method | Weight | CU Value | | :-------------------------------------------------------------------------------- | :----- | :----- | :------- | | `/v1/health-check` | GET | Medium | 20 | | `/v1/address/{address}/chains` | GET | Medium | 20 | | `/v1/transactions` | GET | Medium | 20 | | `/v1/blocks` | GET | Medium | 20 | | `/v1/chains/{chainId}/nfts/collections/{address}/tokens/{tokenId}:reindex` | POST | Small | 10 | | `/v1/chains/{chainId}/nfts/collections/{address}/tokens` | GET | Medium | 20 | | `/v1/chains/{chainId}/nfts/collections/{address}/tokens/{tokenId}` | GET | Medium | 20 | | `/v1/operations/{operationId}` | GET | Small | 10 | | `/v1/operations/transactions:export` | POST | Medium | 20 | | `/v1/networks/{network}/blockchains/{blockchainId}/transactions/{txHash}` | GET | Medium | 20 | | `/v1/networks/{network}/blockchains/{blockchainId}/transactions` | GET | XL | 100 | | `/v1/networks/{network}/blockchains/{blockchainId}/transactions:listStaking` | GET | XL | 100 | | `/v1/networks/{network}/rewards:listPending` | GET | XL | 100 | | `/v1/networks/{network}/rewards` | GET | XL | 100 | | `/v1/networks/{network}/blockchains/{blockchainId}/utxos` | GET | XL | 100 | | `/v1/networks/{network}/blockchains/{blockchainId}/balances` | GET | XL | 100 | | `/v1/networks/{network}/blockchains/{blockchainId}/blocks/{blockId}` | GET | XL | 100 | | `/v1/networks/{network}/blockchains/{blockchainId}/nodes/{nodeId}/blocks` | GET | Medium | 20 | | `/v1/networks/{network}/blockchains/{blockchainId}/blocks` | GET | Medium | 20 | | `/v1/networks/{network}/blockchains/{blockchainId}/vertices` | GET | Medium | 20 | | `/v1/networks/{network}/blockchains/{blockchainId}/vertices/{vertexHash}` | GET | Medium | 20 | | `/v1/networks/{network}/blockchains/{blockchainId}/vertices:listByHeight` | GET | Medium | 20 | | `/v1/networks/{network}/blockchains/{blockchainId}/assets/{assetId}` | GET | XL | 100 | | `/v1/networks/{network}/blockchains/{blockchainId}/assets/{assetId}/transactions` | GET | XL | 100 | | `/v1/networks/{network}/addresses:listChainIds` | GET | XL | 100 | | `/v1/networks/{network}` | GET | XL | 100 | | `/v1/networks/{network}/blockchains` | GET | Medium | 20 | | `/v1/networks/{network}/subnets` | GET | Medium | 20 | | `/v1/networks/{network}/subnets/{subnetId}` | GET | Medium | 20 | | `/v1/networks/{network}/validators` | GET | Medium | 20 | | `/v1/networks/{network}/validators/{nodeId}` | GET | Medium | 20 | | `/v1/networks/{network}/delegators` | GET | Medium | 20 | | `/v1/networks/{network}/l1Validators` | GET | Medium | 20 | | `/v1/teleporter/messages/{messageId}` | GET | Medium | 20 | | `/v1/teleporter/messages` | GET | Medium | 20 | | `/v1/teleporter/addresses/{address}/messages` | GET | Medium | 20 | | `/v1/icm/messages/{messageId}` | GET | Medium | 20 | | `/v1/icm/messages` | GET | Medium | 20 | | `/v1/icm/addresses/{address}/messages` | GET | Medium | 20 | | `/v1/apiUsageMetrics` | GET | XXL | 200 | | `/v1/apiLogs` | GET | XXL | 200 | | `/v1/subnetRpcUsageMetrics` | GET | XXL | 200 | | `/v1/rpcUsageMetrics` | GET | XXL | 200 | | `/v1/primaryNetworkRpcUsageMetrics` | GET | XXL | 200 | | `/v1/signatureAggregator/{network}/aggregateSignatures` | POST | Medium | 20 | | `/v1/signatureAggregator/{network}/aggregateSignatures/{txHash}` | GET | Medium | 20 | | `/v1/chains/{chainId}/addresses/{address}/balances:getNative` | GET | Medium | 20 | | `/v1/chains/{chainId}/addresses/{address}/balances:listErc20` | GET | Medium | 20 | | `/v1/chains/{chainId}/addresses/{address}/balances:listErc721` | GET | Medium | 20 | | `/v1/chains/{chainId}/addresses/{address}/balances:listErc1155` | GET | Medium | 20 | | `/v1/chains/{chainId}/addresses/{address}/balances:listCollectibles` | GET | Medium | 20 | | `/v1/chains/{chainId}/blocks` | GET | Small | 10 | | `/v1/chains/{chainId}/blocks/{blockId}` | GET | Small | 10 | | `/v1/chains/{chainId}/contracts/{address}/transactions:getDeployment` | GET | Medium | 20 | | `/v1/chains/{chainId}/contracts/{address}/deployments` | GET | Medium | 20 | | `/v1/chains/{chainId}/addresses/{address}` | GET | Medium | 20 | | `/v1/chains` | GET | Free | 1 | | `/v1/chains/{chainId}` | GET | Free | 1 | | `/v1/chains/address/{address}` | GET | Free | 1 | | `/v1/chains/allTransactions` | GET | Free | 1 | | `/v1/chains/allBlocks` | GET | Free | 1 | | `/v1/chains/{chainId}/tokens/{address}/transfers` | GET | Medium | 20 | | `/v1/chains/{chainId}/addresses/{address}/transactions` | GET | Medium | 20 | | `/v1/chains/{chainId}/addresses/{address}/transactions:listNative` | GET | Medium | 20 | | `/v1/chains/{chainId}/addresses/{address}/transactions:listErc20` | GET | Medium | 20 | | `/v1/chains/{chainId}/addresses/{address}/transactions:listErc721` | GET | Medium | 20 | | `/v1/chains/{chainId}/addresses/{address}/transactions:listErc1155` | GET | Medium | 20 | | `/v1/chains/{chainId}/addresses/{address}/transactions:listInternals` | GET | Medium | 20 | | `/v1/chains/{chainId}/transactions/{txHash}` | GET | Medium | 20 | | `/v1/chains/{chainId}/blocks/{blockId}/transactions` | GET | Medium | 20 | | `/v1/chains/{chainId}/transactions` | GET | Medium | 20 | {/* data execution weights table end */} ## Rate Limits for RPC endpoints The CUs for RPC calls are calculated based on the RPC method(s) within the request. The CUs assigned to each method are defined in the table below: {/* rpc execution weights table start */} | Method | Weight | CU Value | | :---------------------------------------- | :----- | :------- | | `eth_accounts` | Free | 1 | | `eth_blockNumber` | Small | 10 | | `eth_call` | Small | 10 | | `eth_coinbase` | Small | 10 | | `eth_chainId` | Free | 1 | | `eth_gasPrice` | Small | 10 | | `eth_getBalance` | Small | 10 | | `eth_getBlockByHash` | Small | 10 | | `eth_getBlockByNumber` | Small | 10 | | `eth_getBlockTransactionCountByNumber` | Medium | 20 | | `eth_getCode` | Medium | 20 | | `eth_getLogs` | XXL | 200 | | `eth_getStorageAt` | Medium | 20 | | `eth_getTransactionByBlockNumberAndIndex` | Medium | 20 | | `eth_getTransactionByHash` | Small | 10 | | `eth_getTransactionCount` | Small | 10 | | `eth_getTransactionReceipt` | Small | 10 | | `eth_signTransaction` | Medium | 20 | | `eth_sendTransaction` | Medium | 20 | | `eth_sign` | Medium | 20 | | `eth_sendRawTransaction` | Small | 10 | | `eth_syncing` | Free | 1 | | `net_listening` | Free | 1 | | `net_peerCount` | Medium | 20 | | `net_version` | Free | 1 | | `web3_clientVersion` | Small | 10 | | `web3_sha3` | Small | 10 | | `eth_newPendingTransactionFilter` | Medium | 20 | | `eth_maxPriorityFeePerGas` | Small | 10 | | `eth_baseFee` | Small | 10 | | `rpc_modules` | Free | 1 | | `eth_getChainConfig` | Small | 10 | | `eth_feeConfig` | Small | 10 | | `eth_getActivePrecompilesAt` | Small | 10 | {/* rpc execution weights table end */} All rate limits, weights, and CU values are subject to change. # Aggregate Signatures Source: https://developers.avacloud.io/data-api/signature-aggregator/aggregate-signatures post /v1/signatureAggregator/{network}/aggregateSignatures Aggregates Signatures for a Warp message from Subnet validators. # Get Aggregated Signatures Source: https://developers.avacloud.io/data-api/signature-aggregator/get-aggregated-signatures get /v1/signatureAggregator/{network}/aggregateSignatures/{txHash} Get Aggregated Signatures for a P-Chain L1 related Warp Message. # Snowflake Datashare Source: https://developers.avacloud.io/data-api/snowflake Avalanche Primary Network data (C-chain, P-chain, and X-chain blockchains) can be accessed in a sql-based table format via the [Snowflake Data Marketplace.](https://app.snowflake.com/marketplace) Explore the blockchain state since the Genesis Block. These tables provide insights on transaction gas fees, DeFi activity, the historical stake of validators on the primary network, AVAX emissions rewarded to past validators/delegators, and fees paid by Avalanche L1 Validators to the primary network. ## Available Blockchain Data #### Primary Network * **C-chain:** * Blocks * Transactions * Logs * Internal Transactions * Receipts * Messages * **P-chain:** * Blocks * Transactions * UTXOs * **X-chain:** * Blocks * Transactions * Vertices before the [X-chain Linearization](https://www.avax.network/blog/cortina-x-chain-linearization) in the Cortina Upgrade * **Dictionary:** A data dictionary is provided with the listing with column and table descriptions. Example columns include: * `c_blocks.blockchash` * `c_transactions.transactionfrom` * `c_logs.topichex_0` * `p_blocks.block_hash` * `p_blocks.block_index` * `p_blocks.type` * `p_transactions.timestamp` * `p_transactions.transaction_hash` * `utxos.utxo_id` * `utxos.address` * `vertices.vertex_hash` * `vertices.parent_hash` * `x_blocks.timestamp` * `x_blocks.proposer_id` * `x_transactions.transaction_hash` * `x_transactions.type` #### Avalanche L1s Gunzilla, Dexalot, and DeFi Kingdoms L1 data are currently available. * **Gunzilla:** * Blocks * Transactions * Logs * Internal Transactions * Receipts * Messages * **Dexalot:** * Blocks * Transactions * Logs * Internal Transactions * Receipts * Messages * **DeFi Kingdoms (DFK):** * Blocks * Transactions * Logs * Receipts * Messages ## Access Search for "Ava Labs" on the [Snowflake Data Marketplace](https://app.snowflake.com/marketplace). # null Source: https://developers.avacloud.io/data-api/teleporter/get-a-teleporter-message get /v1/teleporter/messages/{messageId} **[Deprecated]** Gets a teleporter message by message ID. ⚠️ **This operation will be removed in a future release. Please use /v1/icm/messages/:messageId endpoint instead** . # null Source: https://developers.avacloud.io/data-api/teleporter/list-teleporter-messages get /v1/teleporter/messages **[Deprecated]** Lists teleporter messages. Ordered by timestamp in descending order. ⚠️ **This operation will be removed in a future release. Please use /v1/icm/messages endpoint instead** . # null Source: https://developers.avacloud.io/data-api/teleporter/list-teleporter-messages-address get /v1/teleporter/addresses/{address}/messages **[Deprecated]** Lists teleporter messages by address. Ordered by timestamp in descending order. ⚠️ **This operation will be removed in a future release. Please use /v1/icm/addresses/:address/messages endpoint instead** . # Usage Guide Source: https://developers.avacloud.io/data-api/usage-guide ### Setup and Authentication In order to utilize your accounts rate limits, you will need to make API requests with an API key. You can generate API Keys from the AvaCloud portal. Once you've created and retrieved that, you will be able to make authenticated queries by passing in your API key in the `x-glacier-api-key` header of your HTTP request. An example curl request can be found below: ```bash curl -H "Content-Type: Application/json" -H "x-glacier-api-key: your_api_key" \ "https://glacier-api.avax.network/v1/chains" ``` ### Rate Limits The Data API has rate limits in place to maintain it's stability and protect from bursts of incoming traffic. The rate limits associated with various plans can be found within AvaCloud. When you hit your rate limit, the server will respond with a 429 http response code, and response headers to help you determine when you should start to make additional requests. The response headers follow the standards set in the RateLimit header fields for HTTP draft from the Internet Engineering Task Force. With every response with a valid api key, the server will include the following headers: * `ratelimit-policy` - The rate limit policy tied to your api key. * `ratelimit-limit` - The number of requests you can send according to your policy. * `ratelimit-remaining` - How many request remaining you can send in the period for your policy For any request after the rate limit has been reached, the server will also respond with these headers: * `ratelimit-reset` * `retry-after` Both of these headers are set to the number of seconds until your period is over and requests will start succeeding again. If you start receiving rate limit errors with the 429 response code, we recommend you discontinue sending requests to the server. You should wait to retry requests for the duration specified in the response headers. Alternatively, you can implement an exponential backoff algorithm to prevent continuous errors. Failure to discontinue requests may result in being temporarily blocked from accessing the API. Error Types The Data API generates standard error responses along with error codes based on provided requests and parameters. Typically, response codes within the `2XX` range signifies successful requests, while those within the `4XX` range points to errors originating from the client's side. Meanwhile, response codes within the `5XX` range indicates problems on the server's side. ### Error Types The Glacier API generates standard error responses along with error codes based on provided requests and parameters. Typically, response codes within the `2XX` range signifies successful requests, while those within the `4XX` range points to errors originating from the client's side. Meanwhile, response codes within the `5XX` range indicates problems on the server's side. The error response body is formatted like this: ```json { "message": ["Invalid address format"], // route specific error message "error": "Bad Request", // error type "statusCode": 400 // http response code } ``` Let's go through every error code that we can respond with: | Error Code | Error Type | Description | | :--------- | :-------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **400** | Bad Request | Bad requests generally mean the client has passed invalid or malformed parameters. Error messages in the response could help in evaluating the error. | | **401** | Unauthorized | When a client attempts to access resources that require authorization credentials but the client lacks proper authentication in the request, the server responds with 401. | | **403** | Forbidden | When a client attempts to access resources with valid credentials but doesn't have the privilege to perform that action, the server responds with 403. | | **404** | Not Found | The 404 error is mostly returned when the client requests with either mistyped URL, or the passed resource is moved or deleted, or the resource doesn't exist. | | **500** | Internal Server Error | The 500 error is a generic server-side error that is returned for any uncaught and unexpected issues on the server side. This should be very rare, and you may reach out to us if the problem persists for a longer duration. | | **502** | Bad Gateway | This is an internal error indicating invalid response received by the client-facing proxy or gateway from the upstream server. | | **503** | Service Unavailable | The 503 error is returned for certain routes on a particular Subnet. This indicates an internal problem with our Subnet node, and may not necessarily mean the Subnet is down or affected. | The above list is not exhaustive of all the errors that you'll receive, but is categorized on the basis of error codes. You may see route-specific errors along with detailed error messages for better evaluating the response. Reach out to our team when you see an error in the `5XX` range for a longer duration. These errors should be very rare, but we try to fix them as soon as possible once detected. ### Pagination When utilizing pagination for endpoints that return lists of data such as transactions, UTXOs, or blocks, our API uses a straightforward mechanism to manage the navigation through large datasets. We divide data into pages and each page is limited with a `pageSize` number of elements as passed in the request. Users can navigate to subsequent pages using the page token received in the `nextPageToken` field. This method ensures efficient retrieval. Routes with pagination have a following common response format: ```json { "blocks": [""], // This field name will vary by route "nextPageToken": "3d22deea-ea64-4d30-8a1e-c2a353b67e90" } ``` ### Page Token Structure * If there's more data in the dataset for the request, the API will include a UUID-based page token in the response. This token acts as a pointer to the next page of data. * The UUID page token is generated randomly and uniquely for each pagination scenario, enhancing security and minimizing predictability. * It's important to note that the page token is only returned when a next page is present. If there's no further data to retrieve, a page token will not be included in the response. * The generated page token has an expiration window of 24 hours. Beyond this timeframe, the token will no longer be valid for accessing subsequent pages. ### Integration and Usage: To make use of the pagination system, simply examine the API response. If a UUID page token is present, it indicates the availability of additional data on the next page. You can extract this token and include it in the subsequent request to access the subsequent page of results. Please note that you must ensure that the subsequent request is made within the 24-hour timeframe after the original token's generation. Beyond this duration, the token will expire, and you will need to initiate a fresh request from the initial page. By incorporating UUID page tokens, our API offers a secure, efficient, and user-friendly approach to navigating large datasets, streamlining your data retrieval proces ### Swagger API Reference You can explore the full API definitions and interact with the endpoints in the Swagger documentation at: [https://glacier-api.avax.network/api](https://glacier-api.avax.network/api) # Avalanche API Documentation Source: https://developers.avacloud.io/introduction export function openSearch() { document.getElementById("search-bar-entry").click(); }
Avalanche API Documentation

Accelerate your development across 100+ Layer 1 blockchains with powerful SDKs, APIs, guides, and tutorials.

Discover our suite of APIs
Retrieve data from multiple L1s with a few lines of code. Data lake-powered service providing aggregated metrics for dApps. Monitor real-time events on the Avalanche C-Chain and L1s. The Avalanche SDK offers all APIs, allowing developers to build and scale dApps with just a few lines of code.
Avalanche Logo
Crafted with ❤️ by Ava Labs Data & Tooling Team.
# Get metrics for EVM chains Source: https://developers.avacloud.io/metrics-api/chain-metrics/get-metrics-for-evm-chains get /v2/chains/{chainId}/metrics/{metric} EVM chain metrics are available for all Avalanche L1s on _Mainnet_ and _Fuji_ (testnet). You can request metrics by EVM chain ID. See the `/chains` endpoint for all supported chains. All metrics are updated several times every hour. Each metric data point has a `value` and `timestamp` (Unix timestamp in seconds). All metric values include data within the duration of the associated timestamp plus the requested `timeInterval`. All timestamps are fixed to the hour. When requesting a timeInterval of **day**, **week**, or **month**, the timestamp will be 0:00 UTC of the day, Monday of the week, or first day of the month, respectively. The latest data point in any response may change on each update. ### Metrics activeAddresses: The number of distinct addresses seen within the selected `timeInterval` starting at the timestamp. Addresses counted are those that appear in the “from” and “to” fields of a transaction or ERC20/ERC721/ERC1155 transfer log event. activeSenders: This metric follows the same structure as activeAddresses, but instead only counts addresses that appear in the “from” field of the respective transaction or transfer log event. cumulativeTxCount: The cumulative transaction count from genesis up until 24 hours after the timestamp. This aggregation can be considered a “rolling sum” of the transaction count metric (txCount). Only `timeInterval=day` supported. cumulativeAddresses: The cumulative count of unique addresses from genesis up until 24 hours after the timestamp. Addresses counted are those that appear in the “from” and “to” fields of a transaction or ERC20/ERC721/ERC1155 transfer log event. Only `timeInterval=day` supported. cumulativeContracts: The cumulative count of contracts created from genesis up until the timestamp. Contracts are counted by looking for the CREATE, CREATE2, and CREATE3 call types in all transaction traces (aka internal transactions). Only `timeInterval=day` supported. cumulativeDeployers: The cumulative count of unique contract deployers from genesis up until 24 hours after the timestamp. Deployers counted are those that appear in the “from” field of transaction traces with the CREATE, CREATE2, and CREATE3 call types. Only `timeInterval=day` supported. gasUsed: The amount of gas used by transactions within the requested timeInterval starting at the timestamp. txCount: The amount of transactions within the requested timeInterval starting at the timestamp. avgGps: The average Gas used Per Second (GPS) within the day beginning at the timestamp. The average is calculated by taking the sum of gas used by all blocks within the day and dividing it by the time interval between the last block of the previous day and the last block of the day that begins at the timestamp. Only `timeInterval=day` supported. maxGps: The max Gas used Per Second (GPS) measured within the day beginning at the timestamp. Each GPS data point is calculated using the gas used in a single block divided by the time since the last block. Only `timeInterval=day` supported. avgTps: The average Transactions Per Second (TPS) within the day beginning at the timestamp. The average is calculated by taking the sum of transactions within the day and dividing it by the time interval between the last block of the previous day and the last block of the day that begins at the timestamp. Only `timeInterval=day` supported. maxTps: The max Transactions Per Second (TPS) measured within the day beginning at the timestamp. Each TPS data point is calculated by taking the number of transactions in a single block and dividing it by the time since the last block. Only `timeInterval=day` supported. avgGasPrice: The average gas price within the day beginning at the timestamp. The gas price used is the price reported in transaction receipts. Only `timeInterval=day` supported. maxGasPrice: The max gas price seen within the day beginning at the timestamp. The gas price used is the price reported in transaction receipts. Only `timeInterval=day` supported. feesPaid: The sum of transaction fees paid within the day beginning at the timestamp. The fee is calculated as the gas used multiplied by the gas price as reported in all transaction receipts. Only `timeInterval=day` supported. # Get rolling window metrics for EVM chains Source: https://developers.avacloud.io/metrics-api/chain-metrics/get-rolling-window-metrics-for-evm-chains get /v2/chains/{chainId}/rollingWindowMetrics/{metric} Gets the rolling window metrics for an EVM chain for the last hour, day, month, year, and all time. # Get staking metrics for a given subnet Source: https://developers.avacloud.io/metrics-api/chain-metrics/get-staking-metrics-for-a-given-subnet get /v2/networks/{network}/metrics/{metric} Gets staking metrics for a given subnet. # Get teleporter metrics for EVM chains Source: https://developers.avacloud.io/metrics-api/chain-metrics/get-teleporter-metrics-for-evm-chains get /v2/chains/{chainId}/teleporterMetrics/{metric} Gets teleporter metrics for an EVM chain. # Get a list of supported blockchains Source: https://developers.avacloud.io/metrics-api/evm-chains/get-a-list-of-supported-blockchains get /v2/chains Get a list of Metrics API supported blockchains. This endpoint is paginated and supports a maximum page size of 10000. # Get chain information for supported blockchain Source: https://developers.avacloud.io/metrics-api/evm-chains/get-chain-information-for-supported-blockchain get /v2/chains/{chainId} Get chain information for Metrics API supported blockchain. # Getting Started Source: https://developers.avacloud.io/metrics-api/getting-started The Metrics API is designed to be simple and accessible, requiring no authentication to get started. Just choose your endpoint, make your query, and instantly access on-chain data and analytics to power your applications. The following query retrieves the daily count of active addresses on the Avalanche C-Chain(43114) over the course of one month (from August 1, 2024 12:00:00 AM to August 31, 2024 12:00:00 AM), providing insights into user activity on the chain for each day during that period. With this data you can use JavaScript visualization tools like Chart.js, D3.js, Highcharts, Plotly.js, or Recharts to create interactive and insightful visual representations. ```bash curl --request GET \ --url 'https://metrics.avax.network/v2/chains/43114/metrics/activeAddresses?startTimestamp=1722470400&endTimestamp=1725062400&timeInterval=day&pageSize=31' ``` Response: ```json { "results": [ { "value": 37738, "timestamp": 1724976000 }, { "value": 53934, "timestamp": 1724889600 }, { "value": 58992, "timestamp": 1724803200 }, { "value": 73792, "timestamp": 1724716800 }, { "value": 70057, "timestamp": 1724630400 }, { "value": 46452, "timestamp": 1724544000 }, { "value": 46323, "timestamp": 1724457600 }, { "value": 73399, "timestamp": 1724371200 }, { "value": 52661, "timestamp": 1724284800 }, { "value": 52497, "timestamp": 1724198400 }, { "value": 50574, "timestamp": 1724112000 }, { "value": 46999, "timestamp": 1724025600 }, { "value": 45320, "timestamp": 1723939200 }, { "value": 54964, "timestamp": 1723852800 }, { "value": 60251, "timestamp": 1723766400 }, { "value": 48493, "timestamp": 1723680000 }, { "value": 71091, "timestamp": 1723593600 }, { "value": 50456, "timestamp": 1723507200 }, { "value": 46989, "timestamp": 1723420800 }, { "value": 50984, "timestamp": 1723334400 }, { "value": 46988, "timestamp": 1723248000 }, { "value": 66943, "timestamp": 1723161600 }, { "value": 64209, "timestamp": 1723075200 }, { "value": 57478, "timestamp": 1722988800 }, { "value": 80553, "timestamp": 1722902400 }, { "value": 70472, "timestamp": 1722816000 }, { "value": 53678, "timestamp": 1722729600 }, { "value": 70818, "timestamp": 1722643200 }, { "value": 99842, "timestamp": 1722556800 }, { "value": 76515, "timestamp": 1722470400 } ] } ``` Congratulations! You’ve successfully made your first query to the Metrics API. 🚀🚀🚀 # Get the health of the service Source: https://developers.avacloud.io/metrics-api/health-check/get-the-health-of-the-service get /v2/health-check Check the health of the service. # Get addresses by balance over time Source: https://developers.avacloud.io/metrics-api/looking-glass/get-addresses-by-balance-over-time get /v2/chains/{chainId}/contracts/{address}/balances Get list of addresses and their latest balances that have held more than a certain threshold of a given token during the specified time frame. # Get addresses by BTCb bridged balance Source: https://developers.avacloud.io/metrics-api/looking-glass/get-addresses-by-btcb-bridged-balance get /v2/chains/43114/btcb/bridged:getAddresses Get list of addresses and their net bridged amounts that have bridged more than a certain threshold. # Get addresses running validators during a given time frame Source: https://developers.avacloud.io/metrics-api/looking-glass/get-addresses-running-validators-during-a-given-time-frame get /v2/subnets/{subnetId}/validators:getAddresses Get list of addresses and AddValidatorTx timestamps set to receive awards for validation periods during the specified time frame. # Overview Source: https://developers.avacloud.io/metrics-api/overview ### What is the Metrics API? The Metrics API equips web3 developers with a robust suite of tools to access and analyze on-chain activity across Avalanche’s primary network, Avalanche L1s, and other supported EVM chains. This API delivers comprehensive metrics and analytics, enabling you to seamlessly integrate historical data on transactions, gas consumption, throughput, staking, and more into your applications. The Metrics API, along with the [Data API](/data-api) are the driving force behind every graph you see on the [Avalanche Explorer](https://subnets.avax.network/stats/). From transaction trends to staking insights, the visualizations and data presented are all powered by these APIs, offering real-time and historical insights that are essential for building sophisticated, data-driven blockchain products.. ### Features * **Chain Throughput:** Retrieve detailed metrics on gas consumption, Transactions Per Second (TPS), and gas prices, including rolling windows of data for granular analysis. * **Cumulative Metrics:** Access cumulative data on addresses, contracts, deployers, and transaction counts, providing insights into network growth over time. * **Staking Information:** Obtain staking-related data, including the number of validators and delegators, along with their respective weights, across different subnets. * **Blockchains and Subnets:** Get information about supported blockchains, including EVM Chain IDs, blockchain IDs, and subnet associations, facilitating multi-chain analytics. * **Composite Queries:** Perform advanced queries by combining different metric types and conditions, enabling detailed and customizable data retrieval. The Metrics API is designed to provide developers with powerful tools to analyze and monitor on-chain activity across Avalanche’s primary network, Avalanche L1s, and other supported EVM chains. Below is an overview of the key features available: ### Chain Throughput Metrics * **Gas Consumption**
Track the average and maximum gas consumption per second, helping to understand network performance and efficiency. * **Transactions Per Second (TPS)**
Monitor the average and peak TPS to assess the network’s capacity and utilization. * **Gas Prices**
Analyze average and maximum gas prices over time to optimize transaction costs and predict fee trends. Monitor the average and peak TPS to assess the network’s capacity and utilization. ### Cumulative Metrics * **Address Growth**
Access the cumulative number of active addresses on a chain, providing insights into network adoption and user activity. * **Contract Deployment**
Monitor the cumulative number of smart contracts deployed, helping to gauge developer engagement and platform usage. * **Transaction Count**
Track the cumulative number of transactions, offering a clear view of network activity and transaction volume. ### Staking Information * **Validator and Delegator Counts**
Retrieve the number of active validators and delegators for a given L1, crucial for understanding network security and decentralization. * **Staking Weights**
Access the total stake weight of validators and delegators, helping to assess the distribution of staked assets across the network. ### Rolling Window Analytics * **Short-Term and Long-Term Metrics:** Perform rolling window analysis on various metrics like gas used, TPS, and gas prices, allowing for both short-term and long-term trend analysis. * **Customizable Time Frames:** Choose from different time intervals (hourly, daily, monthly) to suit your specific analytical needs. ### Blockchain and L1 Information * **Chain and L1 Mapping:** Get detailed information about EVM chains and their associated L1s, including chain IDs, blockchain IDs, and subnet IDs, facilitating cross-chain analytics. ### Advanced Composite Queries * **Custom Metrics Combinations**: Combine multiple metrics and apply logical operators to perform sophisticated queries, enabling deep insights and tailored analytics. * **Paginated Results:** Handle large datasets efficiently with paginated responses, ensuring seamless data retrieval in your applications. The Metrics API equips developers with the tools needed to build robust analytics, monitoring, and reporting solutions, leveraging the full power of multi-chain data across the Avalanche ecosystem and beyond. # Rate Limits Source: https://developers.avacloud.io/metrics-api/rate-limits Rate limiting is managed through a weighted scoring system, known as Compute Units (CUs). Each API request consumes a specified number of CUs, determined by the complexity of the request. This system is designed to accommodate basic requests while efficiently handling more computationally intensive operations. ## Rate Limit Tiers The maximum CUs (rate-limiting score) for a user depends on their subscription level and is delineated in the following table: | Subscription Level | Per Minute Limit (CUs) | Per Day Limit (CUs) | | :----------------- | :--------------------- | :------------------ | | Free | 8,000 | 1,200,000 | > We are working on new subscription tiers with higher rate limits to support even greater request volumes. ## Rate Limit Categories The CUs for each category are defined in the following table: {/* metrics weights value table start */} | Weight | CU Value | | :----- | :------- | | Free | 1 | | Small | 20 | | Medium | 100 | | Large | 500 | | XL | 1000 | | XXL | 3000 | {/* metrics weights value table end */} ## Rate Limits for Metrics Endpoints The CUs for each route are defined in the table below: {/* metrics execution weights table start */} | Endpoint | Method | Weight | CU Value | | :---------------------------------------------------------- | :----- | :----- | :------- | | `/v2/health-check` | GET | Free | 1 | | `/v2/chains` | GET | Free | 1 | | `/v2/chains/{chainId}` | GET | Free | 1 | | `/v2/chains/{chainId}/metrics/{metric}` | GET | Medium | 100 | | `/v2/chains/{chainId}/teleporterMetrics/{metric}` | GET | Medium | 100 | | `/v2/chains/{chainId}/rollingWindowMetrics/{metric}` | GET | Medium | 100 | | `/v2/networks/{network}/metrics/{metric}` | GET | Medium | 100 | | `/v2/chains/{chainId}/contracts/{address}/nfts:listHolders` | GET | Large | 500 | | `/v2/chains/{chainId}/contracts/{address}/balances` | GET | XL | 1000 | | `/v2/chains/43114/btcb/bridged:getAddresses` | GET | Large | 500 | | `/v2/subnets/{subnetId}/validators:getAddresses` | GET | Large | 500 | | `/v2/lookingGlass/compositeQuery` | POST | XXL | 3000 | {/* metrics execution weights table end */} All rate limits, weights, and CU values are subject to change. # Usage Guide Source: https://developers.avacloud.io/metrics-api/usage-guide The Metrics API does not require authentication, making it straightforward to integrate into your applications. You can start making API requests without the need for an API key or any authentication headers. #### Making Requests You can interact with the Metrics API by sending HTTP GET requests to the provided endpoints. Below is an example of a simple `curl` request. ```bash curl -H "Content-Type: Application/json" "https://metrics.avax.network/v1/avg_tps/{chainId}" ``` In the above request Replace `chainId` with the specific chain ID you want to query. For example, to retrieve the average transactions per second (TPS) for a specific chain (in this case, chain ID 43114), you can use the following endpoint: ```bash curl "https://metrics.avax.network/v1/avg_tps/43114" ``` The API will return a JSON response containing the average TPS for the specified chain over a series of timestamps and `lastRun` is a timestamp indicating when the last data point was updated: ```json { "results": [ {"timestamp": 1724716800, "value": 1.98}, {"timestamp": 1724630400, "value": 2.17}, {"timestamp": 1724544000, "value": 1.57}, {"timestamp": 1724457600, "value": 1.82}, // Additional data points... ], "status": 200, "lastRun": 1724780812 } ``` ### Rate Limits Even though the Metrics API does not require authentication, it still enforces rate limits to ensure stability and performance. If you exceed these limits, the server will respond with a 429 Too Many Requests HTTP response code. ### Error Types The API generates standard error responses along with error codes based on provided requests and parameters. Typically, response codes within the `2XX` range signifies successful requests, while those within the `4XX` range points to errors originating from the client's side. Meanwhile, response codes within the `5XX` range indicates problems on the server's side. The error response body is formatted like this: ```json { "message": ["Invalid address format"], // route specific error message "error": "Bad Request", // error type "statusCode": 400 // http response code } ``` Let's go through every error code that we can respond with: | Error Code | Error Type | Description | | ---------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **400** | Bad Request | Bad requests generally mean the client has passed invalid or malformed parameters. Error messages in the response could help in evaluating the error. | | **401** | Unauthorized | When a client attempts to access resources that require authorization credentials but the client lacks proper authentication in the request, the server responds with 401. | | **403** | Forbidden | When a client attempts to access resources with valid credentials but doesn't have the privilege to perform that action, the server responds with 403. | | **404** | Not Found | The 404 error is mostly returned when the client requests with either mistyped URL, or the passed resource is moved or deleted, or the resource doesn't exist. | | **500** | Internal Server Error | The 500 error is a generic server-side error that is returned for any uncaught and unexpected issues on the server side. This should be very rare, and you may reach out to us if the problem persists for a longer duration. | | **502** | Bad Gateway | This is an internal error indicating invalid response received by the client-facing proxy or gateway from the upstream server. | | **503** | Service Unavailable | The 503 error is returned for certain routes on a particular Subnet. This indicates an internal problem with our Subnet node, and may not necessarily mean the Subnet is down or affected. | ### Pagination For endpoints that return large datasets, the Metrics API employs pagination to manage the results. When querying for lists of data, you may receive a nextPageToken in the response, which can be used to request the next page of data. Example response with pagination: ```json { "results": [...], "nextPageToken": "3d22deea-ea64-4d30-8a1e-c2a353b67e90" } ``` To retrieve the next set of results, include the nextPageToken in your subsequent request: ```bash curl -H "Content-Type: Application/json" \ "https://metrics.avax.network/v1/avg_tps/{chainId}?pageToken=3d22deea-ea64-4d30-8a1e-c2a353b67e90" ``` ### Pagination Details #### Page Token Structure The `nextPageToken` is a UUID-based token provided in the response when additional pages of data are available. This token serves as a pointer to the next set of data. * **UUID Generation**: The `nextPageToken` is generated uniquely for each pagination scenario, ensuring security and ensuring predictability. * **Expiration**: The token is valid for 24 hours from the time it is generated. After this period, the token will expire, and a new request starting from the initial page will be required. * **Presence**: The token is only included in the response when there is additional data available. If no more data exists, the token will not be present. #### Integration and Usage To use the pagination system effectively: * Check if the `nextPageToken` is present in the response. * If present, include this token in the subsequent request to fetch the next page of results. * Ensure that the follow-up request is made within the 24-hour window after the token was generated to avoid token expiration. By utilizing the pagination mechanism, you can efficiently manage and navigate through large datasets, ensuring a smooth data retrieval process. ### Swagger API Reference You can explore the full API definitions and interact with the endpoints in the Swagger documentation at: [https://metrics.avax.network/api](https://metrics.avax.network/api) # Track ERC-20 Transfers Source: https://developers.avacloud.io/webhooks-api/erc20-transfers In a smart contract, events serve as notifications of specific occurrences, like transactions, or changes in ownership. Each event is uniquely identified by its event signature, which is calculated using the keccak 256 hash of the event name and its input argument types. For example, for an ERC-20 transfer event, the event signature is determined by taking the hash of `Transfer(address,address,uint256)`. To compute this hash yourself, you can use an online `keccak-256` converter and you’ll see that the hexadecimal representation of Transfer(address,address,uint256) is 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. For a full list of signatures check [https://www.4byte.directory/event-signatures/](https://www.4byte.directory/event-signatures/). Take into consideration that the Transfer event for ERC-20 and ERC-721 tokens is similar. Here is the Transfer event prototype on each standard: * **ERC20**:\ `event Transfer(address indexed _from, address indexed _to, uint256 _value);` * **ERC721**:\ `event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);` These two signatures are indeed the same when you hash them to identify `Transfer` events. The example below illustrates how to set up filtering to receive transfer events. In this example, we will monitor all the USDT transfers on the C-chain. If we go to any block explorer, select a USDT transaction, and look at `Topic 0` from the transfer event, we can get the signature. With the event signature, we can create the webhook as follows: ```bash curl --location ' --header 'x-glacier-api-key: ' \ --header 'Content-Type: application/json' \ --data '{ "url": "https://webhook.site/961a0d1b-a7ed-42fd-9eab-d7e4c7eb1227", "chainId": "43114", "eventType": "address_activity", "metadata": { "addresses": ["0x54C800d2331E10467143911aabCa092d68bF4166"], "includeInternalTxs": false, "includeLogs": true, "eventSignatures": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" ] }, "name": "Dokyo NFT", "description": "Dokyo NFT" }' ``` Whenever an NFT is transferred you’ll receive a payload like this: ```json { "webhookId": "6d1bd383-aa8d-47b5-b793-da6d8a115fde", "eventType": "address_activity", "messageId": "6a364b45-47a2-45af-97c3-0ddc2e87ad36", "event": { "transaction": { "blockHash": "0x30da6a8887bf2c26b7921a1501abd6e697529427e4a4f52a9d4fc163a2344b46", "blockNumber": "42649820", "from": "0x0000333883f313AD709f583D0A3d2E18a44EF29b", "gas": "245004", "gasPrice": "30000000000", "maxFeePerGas": "30000000000", "maxPriorityFeePerGas": "30000000000", "txHash": "0x2f1a9e2b8719536997596d878f21b70f2ce0901287aa3480d923e7ffc68ac3bc", "txStatus": "1", "input": "0xafde1b3c0000000000000000000000000…0000000000000000000000000000000000", "nonce": "898", "to": "0x398baa6ffc99126671ab6be565856105a6118a40", "transactionIndex": 0, "value": "0", "type": 0, "chainId": "43114", "receiptCumulativeGasUsed": "163336", "receiptGasUsed": "163336", "receiptEffectiveGasPrice": "30000000000", "receiptRoot": "0xdf05c214cee5ff908744e13a3b2879fdba01c9c7f95073670cb23ed735126178", "contractAddress": "0x0000000000000000000000000000000000000000", "blockTimestamp": 1709930290 }, "logs": [ { "address": "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7", "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "topic1": "0x0000000000000000000000008cdd7a500f21455361cf1c2e01c0525ce92481b2", "topic2": "0x0000000000000000000000000000333883f313ad709f583d0a3d2e18a44ef29b", "topic3": null, "data": "0x000000000000000000000000000000000000000000000001a6c5c6f4f4f6d060", "transactionIndex": 0, "logIndex": 0, "removed": false }, { "address": "0x54C800d2331E10467143911aabCa092d68bF4166", "topic0": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", "topic1": "0x0000000000000000000000000000333883f313ad709f583d0a3d2e18a44ef29b", "topic2": "0x0000000000000000000000000000000000000000000000000000000000000000", "topic3": "0x0000000000000000000000000000000000000000000000000000000000001350", "data": "0x", "transactionIndex": 0, "logIndex": 1, "removed": false }, { "address": "0x54C800d2331E10467143911aabCa092d68bF4166", "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "topic1": "0x0000000000000000000000000000333883f313ad709f583d0a3d2e18a44ef29b", "topic2": "0x0000000000000000000000008cdd7a500f21455361cf1c2e01c0525ce92481b2", "topic3": "0x0000000000000000000000000000000000000000000000000000000000001350", "data": "0x", "transactionIndex": 0, "logIndex": 2, "removed": false }, { "address": "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7", "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "topic1": "0x0000000000000000000000008cdd7a500f21455361cf1c2e01c0525ce92481b2", "topic2": "0x00000000000000000000000087f45335268512cc5593d435e61df4d75b07d2a2", "topic3": null, "data": "0x000000000000000000000000000000000000000000000000087498758a04efb0", "transactionIndex": 0, "logIndex": 3, "removed": false }, { "address": "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7", "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "topic1": "0x0000000000000000000000008cdd7a500f21455361cf1c2e01c0525ce92481b2", "topic2": "0x000000000000000000000000610512654af4fa883bb727afdff2dd78b65342b7", "topic3": null, "data": "0x000000000000000000000000000000000000000000000000021d261d62813bec", "transactionIndex": 0, "logIndex": 4, "removed": false }, { "address": "0x398BAa6FFc99126671Ab6be565856105a6118A40", "topic0": "0x50273fa02273cceea9cf085b42de5c8af60624140168bd71357db833535877af", "topic1": null, "topic2": null, "topic3": null, "data": "0x0000000000009911a89f400000000000000000000…0000010", "transactionIndex": 0, "logIndex": 5, "removed": false } ] } } ``` # Getting Started Source: https://developers.avacloud.io/webhooks-api/getting-started Creating a webhook using the AvaCloud portal There are many websites you can use to test out webhooks. For example, you can use [https://webhook.site/](https://webhook.site/) and copy your unique URL. Once you have the URL, you can test using the following steps: 1. Navigate to the [Avacloud Dashboard](https://app.avacloud.io/) and click on **Web3 Data API** 2. Click **Create Webhook** 3. Fill out the form with the unique URL generated in `https://webhook.site/` and the address you want to monitor. In this example, we want to monitor USDC on the mainnet. The address for the USDC contract is the C-chain is `0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E`. 4. Click **Create** and go to \`[https://webhook.site/](https://webhook.site/), you should see something like this: ## Managing webhooks using Glacier API You can programmatically manage webhooks using Glacier API. For example: 1. Navigate to the [Avacloud Dashboard](https://app.avacloud.io/) and click on **Web3 Data API** 2. Click on **Add API Key** 3. Copy your API key and use it to create a webhook. For example: ```bash curl --location 'https://glacier-api.avax.network/v1/webhooks' \ --header 'Content-Type: application/json' \ --header 'x-glacier-api-key: ' \ --data '{ "url": "https://webhook.site/af5cfd05-d104-4573-8ff0-6f11dffbf1eb", "chainId": "43114", "eventType": "address_activity", "metadata": { "addresses": ["0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E"] }, "name": "Dokyo", "description": "Dokyo NFT" "includeInternalTxs": true, "includeLogs": True }' ``` Use all Glacier methods at your convenience to `create`, `update`, `delete` or `list` the webhooks in your account. ### Local testing with a Node.js Express app If we want to test the webhook in our computer and we are behind a proxy/NAT device or a firewall we need a tool like Ngrok. Avacloud will trigger the webhook and make a POST to the Ngrok cloud, then the request is forwarded to your local Ngrok client who in turn forwards it to the Node.js app listening on port 8000. Go to [https://ngrok.com/](https://ngrok.com/) create a free account, download the binary, and connect to your account. Create a Node.js app with Express and paste the following code to receive the webhook: ```javascript const express = require('express'); const app = express(); app.post('/callback', express.json({ type: 'application/json' }), (request, response) => { const { body, headers } = request; // Handle the event switch (body.eventType) { case 'address_activity': console.log("*** Address_activity ***"); console.log(body); break; // ... handle other event types default: console.log(`Unhandled event type ${body}`); } // Return a response to acknowledge receipt of the event response.json({ received: true }); }); const PORT = 8000; app.listen(PORT, () => console.log(`Running on port ${PORT}`)); ``` Run the app with the following command: ```shell node app.js The Express app will be listening on port 8000. To start an HTTP tunnel forwarding to your local port 8000 with Ngrok, run this next: ``` ```shell ./ngrok http 8000 ``` You should see something like this: ```bash ngrok (Ctrl+C to quit) Take our ngrok in production survey! https://forms.gle/aXiBFWzEA36DudFn6 Session Status online Account javier.toledo@avalabs.org (Plan: Free) Update update available (version 3.7.0, Ctrl-U to update) Version 3.5.0 Region United States (us) Latency - Web Interface http://127.0.0.1:4040 Forwarding https://825a-2600-1700-5220-11a0-385f-7786-5e74-32cb.ngrok-free.app -> http://localhost:8000 Connections ttl opn rt1 rt5 p50 p90 0 0 0.00 0.00 0.00 0.00 ``` Copy the HTTPS forwarding URL and append the `/callbackpath` and type the address you want to monitor. If we transfer AVAX to the address we will detect the payment and the webhook will be triggered. Now we can receive the event on our local server. The response should be something like this: ```json { "webhookId": "8ca68f98-18e5-47fb-a669-9ba7a6ed32b0", "eventType": "address_activity", "messageId": "ad66c866-17b4-44f7-9485-32211170da86", "event": { "transaction": { "blockHash": "0x924ab683b4eba825410b8f233297927aa91af9483fe2d7dd799afbe0e70ea2db", "blockNumber": "42776050", "from": "0x4962aE47413a39fe219e17679124DF0086f0C369", "gas": "296025", "gasPrice": "35489466312", "maxFeePerGas": "35489466312", "maxPriorityFeePerGas": "1500000000", "txHash": "0x9d3b6efae152cd17a30e5522b07d7217a9809a4a437b3269ded7474cfdecd167", "txStatus": "1", "input": "0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065ef6db400000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000009b6e64a8ec600000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000009b6e64a8ec60000000000000000000000000000000000000000000000000001d16b69c3febc194200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042b31f66aa3c1e785363f0875a1b74e27b85fd66c70001f4b97ef9ef8734c71904d8002f8b6bc66dd9c48a6e000bb8d586e7f844cea2f87f50152665bcbc2c279d8d70000000000000000000000000000000000000000000000000000000000000", "nonce": "0", "to": "0x4dae2f939acf50408e13d58534ff8c2776d45265", "transactionIndex": 17, "value": "700000000000000000", "type": 2, "chainId": "43114", "receiptCumulativeGasUsed": "2215655", "receiptGasUsed": "244010", "receiptEffectiveGasPrice": "28211132966", "receiptRoot": "0x40d0ea00b2ce9e72a4bdebfbdc8dd4d73ebecbf80f1c107993eb78a5d28a44bf", "contractAddress": "0x0000000000000000000000000000000000000000", "blockTimestamp": 1710189471 }, "logs": [ { "address": "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7", "topic0": "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", "topic1": "0x0000000000000000000000004dae2f939acf50408e13d58534ff8c2776d45265", "topic2": null, "topic3": null, "data": "0x00000000000000000000000000000000000000000000000009b6e64a8ec60000", "transactionIndex": 17, "logIndex": 39, "removed": false }, { "address": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E", "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "topic1": "0x000000000000000000000000fae3f424a0a47706811521e3ee268f00cfb5c45e", "topic2": "0x0000000000000000000000004dae2f939acf50408e13d58534ff8c2776d45265", "topic3": null, "data": "0x00000000000000000000000000000000000000000000000000000000020826ca", "transactionIndex": 17, "logIndex": 40, "removed": false }, { "address": "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7", "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "topic1": "0x0000000000000000000000004dae2f939acf50408e13d58534ff8c2776d45265", "topic2": "0x000000000000000000000000fae3f424a0a47706811521e3ee268f00cfb5c45e", "topic3": null, "data": "0x00000000000000000000000000000000000000000000000009b6e64a8ec60000", "transactionIndex": 17, "logIndex": 41, "removed": false }, { "address": "0xfAe3f424a0a47706811521E3ee268f00cFb5c45E", "topic0": "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67", "topic1": "0x0000000000000000000000004dae2f939acf50408e13d58534ff8c2776d45265", "topic2": "0x0000000000000000000000004dae2f939acf50408e13d58534ff8c2776d45265", "topic3": null, "data": "0x00000000000000000000000000000000000000000000000009b6e64a8ec60000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffdf7d93600000000000000000000000000000000000000000000751b593c19962c0ca27000000000000000000000000000000000000000000000000006d2063b8b0f00effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc606b", "transactionIndex": 17, "logIndex": 42, "removed": false }, { "address": "0xd586E7F844cEa2F87f50152665BCbc2C279D8d70", "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "topic1": "0x000000000000000000000000a7141c79d3d4a9ad67ba95d2b97fe7eed9fb92b3", "topic2": "0x0000000000000000000000004962ae47413a39fe219e17679124df0086f0c369", "topic3": null, "data": "0x000000000000000000000000000000000000000000000001d75d7654d90a2700", "transactionIndex": 17, "logIndex": 43, "removed": false }, { "address": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E", "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "topic1": "0x0000000000000000000000004dae2f939acf50408e13d58534ff8c2776d45265", "topic2": "0x000000000000000000000000a7141c79d3d4a9ad67ba95d2b97fe7eed9fb92b3", "topic3": null, "data": "0x00000000000000000000000000000000000000000000000000000000020826ca", "transactionIndex": 17, "logIndex": 44, "removed": false }, { "address": "0xA7141C79d3d4a9ad67bA95D2b97Fe7EeD9fB92B3", "topic0": "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67", "topic1": "0x0000000000000000000000004dae2f939acf50408e13d58534ff8c2776d45265", "topic2": "0x0000000000000000000000004962ae47413a39fe219e17679124df0086f0c369", "topic3": null, "data": "0x00000000000000000000000000000000000000000000000000000000020826cafffffffffffffffffffffffffffffffffffffffffffffffe28a289ab26f5d90000000000000000000000000000000000000f410a3539e2dfdf2b8bb00e7cab2f00000000000000000000000000000000000000000000000099a49d85f5d9286a000000000000000000000000000000000000000000000000000000000004375d", "transactionIndex": 17, "logIndex": 45, "removed": false } ] } } ``` # Monitoring multiple addresses Source: https://developers.avacloud.io/webhooks-api/multiple A single webhook can monitor multiple addresses, you don't need to create one webhook per address. In the free plan, you add up to 5 addresses per webhook. If you need more than that you can upgrade your plan. ### Creating the webhook Let's start by creating a new webhook to monitor all USDC and USDT activity: ```bash curl --location 'https://glacier-api.avax.network/v1/webhooks' \ --header 'x-glacier-api-key: ' \ --header 'Content-Type: application/json' \ --data '{ "url": "https://webhook.site/4eb31e6c-a088-4dcb-9a5d-e9341624b584", "chainId": "43114", "eventType": "address_activity", "includeInternalTxs": true, "includeLogs": true, "metadata": { "addresses": [ "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7", "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E" ] }, "name": "Tokens", "description": "Track tokens" } ``` It returns the following: ```json { "id": "401da7d9-d6d7-46c8-b431-72ff1e1543f4", "eventType": "address_activity", "chainId": "43114", "metadata": { "addresses": [ "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7", "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E" ] }, "includeInternalTxs": true, "includeLogs": true, "url": "https://webhook.site/4eb31e6c-a088-4dcb-9a5d-e9341624b584", "status": "active", "createdAt": 1715621587726, "name": "Tokens", "description": "Track tokens" } ``` ### Adding addresses to monitor With the webhook `id` we can add more addresses. In this case, let's add the contract addresses for JOE and PNG: ```bash curl --location --request PATCH 'https://glacier-api.avax.network/v1/webhooks/401da7d9-d6d7-46c8-b431-72ff1e1543f4/addresses' \ --header 'x-glacier-api-key: ' \ --header 'Content-Type: application/json' \ --data '{ "addresses": [ "0x6e84a6216eA6dACC71eE8E6b0a5B7322EEbC0fDd", "0x60781C2586D68229fde47564546784ab3fACA982" ] } ``` Following that, we will begin to receive events from the four smart contracts integrated into the webhook: USDC, USDT, JOE, and PNG. ### Deleting addresses To remove addresses, simply send an array: ```bash curl --location --request DELETE 'https://glacier-api.avax.network/v1/webhooks/401da7d9-d6d7-46c8-b431-72ff1e1543f4/addresses' \ --header 'x-glacier-api-key: You can subscribe to multiple sub-events in a single webhook, reducing the number of subscriptions you need to manage. *** ## What Data Will You Receive? When an event triggers your webhook, you’ll receive a JSON payload with details about the event. Here’s what to expect for each event: ## Balance change This notification describes a successful import of 5 AVAX from the C-chain to the P-chain for the address `fuji1xp395ktf5kqfv9qyv2astt6fhnc4605pqwrf40`. The balance change event describes an ImportTx transaction on the Avalanche Fuji testnet where: 1. The address `fuji1xp395ktf5kqfv9qyv2astt6fhnc4605pqwrf40` had 5 AVAX (5,000,000,000 nanoAVAX) pending import from the X-Chain. 2. The transaction `2F1b1kWAGFrGQYoVzPS8DzSYhwcix1JgYb9ctDpw4teNp8QiKS` successfully imported these funds to the P-Chain. 3. A fee of 4,135 nanoAVAX was paid, resulting in a final balance of 4,999,995,865 nanoAVAX (approximately 4.999995865 AVAX) on the P-Chain, categorized as `unlockedUnstaked`. If a webhook is created with 10 addresses and an event (tx) is triggered involving 4 addresses—only 3 of which match the webhook subscription—the balance change event will return the combined balance of those 3 matching addresses. ```json {3,6,8} [expandable] { "webhookId": "c16f9dd6-9e07-49cd-bee2-7770cd797278", "eventType": "platform_address_activity", "messageId": "5101a28a-da03-479f-a0f9-6499014689bc", "event": { "eventType": "balance_change", "addresses": [ "fuji1xp395ktf5kqfv9qyv2astt6fhnc4605pqwrf40" ], "timestamp": 1742409843, "initialBalance": { "balances": { "unlockedStaked": [ ], "unlockedUnstaked": [ ], "lockedStaked": [ ], "lockedPlatform": [ ], "lockedStakeable": [ ], "pendingStaked": [ ], "atomicMemoryLocked": [ ], "atomicMemoryUnlocked": [ { "assetId": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "5000000000", "utxoCount": 1, "status": "pendingImport", "sharedWithChainId": "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp" } ] }, "chainInfo": { "chainName": "p-chain", "network": "fuji" } }, "finalBalance": { "balances": { "unlockedStaked": [ ], "unlockedUnstaked": [ { "assetId": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "4999995865", "utxoCount": 1 } ], "lockedStaked": [ ], "lockedPlatform": [ ], "lockedStakeable": [ ], "pendingStaked": [ ], "atomicMemoryLocked": [ ], "atomicMemoryUnlocked": [ ] }, "chainInfo": { "chainName": "p-chain", "network": "fuji" } }, "tx": { "txHash": "2F1b1kWAGFrGQYoVzPS8DzSYhwcix1JgYb9ctDpw4teNp8QiKS", "txType": "ImportTx", "blockTimestamp": 1742409843, "blockNumber": "203660", "blockHash": "26Q16Kson46jqWML9zyjwFaHksNk9xx1JojP1DaT9VtjLHBQS", "sourceChain": "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp", "destinationChain": "11111111111111111111111111111111LpoYY", "memo": "0x", "consumedUtxos": [ { "addresses": [ "fuji1xp395ktf5kqfv9qyv2astt6fhnc4605pqwrf40" ], "utxoId": "2KowNALbesyXaTJu2CrXuwGPo3jdEDwCymM9PCSg7v7ZM6PPz5", "txHash": "ACeSGBDHqJtmYtyHvsFgKFY7zwJKrwcJuQFdaPsw2yp3PMwEE", "outputIndex": 0, "blockTimestamp": 1742409832, "blockNumber": "38708400", "consumingTxHash": "2F1b1kWAGFrGQYoVzPS8DzSYhwcix1JgYb9ctDpw4teNp8QiKS", "consumingBlockTimestamp": 1742409843, "consumingBlockNumber": "203660", "assetId": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", "asset": { "assetId": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "5000000000" }, "utxoType": "TRANSFER", "amount": "5000000000", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": false } ], "emittedUtxos": [ { "addresses": [ "fuji1xp395ktf5kqfv9qyv2astt6fhnc4605pqwrf40" ], "utxoId": "2bD3ygVJURRtKPjuwZU9iPcBteRdzez6Fbb3XFxxxv1cDy1UXX", "txHash": "2F1b1kWAGFrGQYoVzPS8DzSYhwcix1JgYb9ctDpw4teNp8QiKS", "outputIndex": 0, "blockTimestamp": 1742409843, "blockNumber": "203660", "assetId": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", "asset": { "assetId": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "4999995865" }, "utxoType": "TRANSFER", "amount": "4999995865", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": false } ], "value": [ { "assetId": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "4999995865" } ], "amountBurned": [ { "assetId": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "4135" } ], "amountStaked": [ { "assetId": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "0" } ], "amountL1ValidatorBalanceBurned": [ { "assetId": "U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "0" } ] } } } ``` *** ## Reward distribution This payload shows a successful reward distribution event. The delegator staked 187.4115 AVAX with a validator for approximately 14 days and earned a reward of 0.4186 AVAX, which was paid out to their designated address. **Delegation:** * On September 5, 2025, the delegator staked approximately 187.4115 AVAX with the validator `NodeID-9odH3Jbw7uPuRrbaVkVoYeitdzwX6o69A` via transaction `2AD5bSwqK7iTSkDqzYHXDeEeipWKHAsUsHoPy4bpuVzEP2AdEN` * The staking period lasted about 14.2 days, ending on September 18, 2025. **Reward Distribution:** * At the end of the staking period, the delegator received a reward of approximately **0.4186 AVAX**, distributed via transaction `2DP6xCr6MfLpwPrkzw5A2cNRZrJLwQpt1VB6uQZyDjS9NJdHgT`. * The reward was sent to `avax19zfygxaf59stehzedhxjesads0p5jdvfeedal0` * The actual reward is **0.4271 AVAX**. ```json {3,7,8,11,12,23,43,44,183} [expandable] { "webhookId": "89266b1b-61a1-40f7-a309-59af999a048b", "eventType": "validator_activity", "messageId": "396356c9-037c-416a-a36f-1b7f70e0574e", "event": { "eventType": "reward_distribution", "nodeID": "NodeID-9odH3Jbw7uPuRrbaVkVoYeitdzwX6o69A", "subnetID": "11111111111111111111111111111111LpoYY", "rewardAddresses": ["avax19zfygxaf59stehzedhxjesads0p5jdvfeedal0"], "amount": "418590717", "rewardType": "DELEGATOR", "rewardTxHash": "2DP6xCr6MfLpwPrkzw5A2cNRZrJLwQpt1VB6uQZyDjS9NJdHgT", "stakingTxHash": "2AD5bSwqK7iTSkDqzYHXDeEeipWKHAsUsHoPy4bpuVzEP2AdEN", "rewardTx": { "txHash": "2DP6xCr6MfLpwPrkzw5A2cNRZrJLwQpt1VB6uQZyDjS9NJdHgT", "txType": "RewardValidatorTx", "blockTimestamp": 1742844464, "blockNumber": "20994230", "blockHash": "2E9vKCP9fqNSkCR5JBXFBN9aCaiUdhr6TQVr6q5EzSMH5QNxwr", "memo": "", "stakingTxHash": "2AD5bSwqK7iTSkDqzYHXDeEeipWKHAsUsHoPy4bpuVzEP2AdEN", "rewardAddresses": ["avax19zfygxaf59stehzedhxjesads0p5jdvfeedal0"], "nodeId": "NodeID-9odH3Jbw7uPuRrbaVkVoYeitdzwX6o69A", "subnetId": "11111111111111111111111111111111LpoYY", "consumedUtxos": [], "emittedUtxos": [], "value": [], "amountBurned": [], "amountStaked": [], "amountL1ValidatorBalanceBurned": [] }, "stakingTx": { "txHash": "2AD5bSwqK7iTSkDqzYHXDeEeipWKHAsUsHoPy4bpuVzEP2AdEN", "txType": "AddPermissionlessDelegatorTx", "blockTimestamp": 1741616501, "blockNumber": "20892409", "blockHash": "2dGUzofDNRiS5rBV5v9117cruTg5ye6t6Nan8NxZPr3yHwXBd7", "memo": "0x", "rewardAddresses": ["avax19zfygxaf59stehzedhxjesads0p5jdvfeedal0"], "rewardTxHash": "2DP6xCr6MfLpwPrkzw5A2cNRZrJLwQpt1VB6uQZyDjS9NJdHgT", "estimatedReward": "427133385", "startTimestamp": 1741616501, "endTimestamp": 1742844464, "nodeId": "NodeID-9odH3Jbw7uPuRrbaVkVoYeitdzwX6o69A", "subnetId": "11111111111111111111111111111111LpoYY", "consumedUtxos": [ { "addresses": ["avax1tnuesf6cqwnjw7fxjyk7lhch0vhf0v95wj5jvy"], "utxoId": "2VnBenu1FEjhdmrjCXkYDEZk5o55ktYyaSqxprTBZaWVSGmwN1", "txHash": "2Nj6eZ28RZqNesbFSeTrU321y33PKcbS7s4JAypJbdULLUhEN6", "outputIndex": 0, "blockTimestamp": 1741616499, "blockNumber": "20892408", "consumingTxHash": "2AD5bSwqK7iTSkDqzYHXDeEeipWKHAsUsHoPy4bpuVzEP2AdEN", "consumingBlockTimestamp": 1741616501, "consumingBlockNumber": "20892409", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "309353245914" }, "utxoType": "TRANSFER", "amount": "309353245914", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": false } ], "emittedUtxos": [ { "addresses": ["avax1tnuesf6cqwnjw7fxjyk7lhch0vhf0v95wj5jvy"], "utxoId": "ChNnDNhk7uNFeEeyZS4eupKELvVudapPoVVjNdqZvRcXdZD8Y", "txHash": "2AD5bSwqK7iTSkDqzYHXDeEeipWKHAsUsHoPy4bpuVzEP2AdEN", "outputIndex": 0, "blockTimestamp": 1741616501, "blockNumber": "20892409", "consumingTxHash": "FHFNCnGJgy6iTA1ePUwgfWq5VAv2vGiY74P5B5b7NWUsoRQUk", "consumingBlockTimestamp": 1741616503, "consumingBlockNumber": "20892410", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "121941742101" }, "utxoType": "TRANSFER", "amount": "121941742101", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": false }, { "addresses": ["avax1tnuesf6cqwnjw7fxjyk7lhch0vhf0v95wj5jvy"], "utxoId": "fWw6hCrtTAWzid3gnZWoAML9dGLrTSKwme9NgDsKAd25zQeRK", "txHash": "2AD5bSwqK7iTSkDqzYHXDeEeipWKHAsUsHoPy4bpuVzEP2AdEN", "outputIndex": 1, "blockTimestamp": 1741616501, "blockNumber": "20892409", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "187411495514" }, "utxoType": "TRANSFER", "amount": "187411495514", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": true, "utxoStartTimestamp": 1741616501, "utxoEndTimestamp": 1742844464 }, { "addresses": ["avax19zfygxaf59stehzedhxjesads0p5jdvfeedal0"], "utxoId": "qJmWca11ztcU6zemVBsmgpFD5YPWDAHpYvKitw7tRsbcYH1gi", "txHash": "2AD5bSwqK7iTSkDqzYHXDeEeipWKHAsUsHoPy4bpuVzEP2AdEN", "outputIndex": 2, "blockTimestamp": 1742844464, "blockNumber": "20994230", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "418590717" }, "utxoType": "TRANSFER", "amount": "418590717", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": false, "rewardType": "DELEGATOR" } ], "value": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "309771828332" } ], "amountBurned": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "8299" } ], "amountStaked": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "187411495514" } ], "amountL1ValidatorBalanceBurned": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "0" } ] } } } ``` *** ## Balance Threshold The `balance_threshold_platform` event is triggered when the balance of specified key addresses falls below a given threshold. On the P-Chain and X-Chain, multiple balance types exist, which you can explore [here](https://developers.avacloud.io/data-api/primary-network-balances/get-balances#response-balances). To track this event, users must provide both a balanceType and a balanceThreshold (in nAVAX). This event is only triggered when the post-transaction balance is lower than the specified threshold, and the pre-transaction balance was higher. **Details it includes:** * Which addresses are affected (`addresses`: a list of account IDs). * When it happened (`timestamp`). * What kind of balance is being tracked (`balanceType`). * The minimum limit that was crossed (`threshold`). * The balance before the transaction (`initialBalance`). * The balance after the transaction (`finalBalance`). * The transaction that caused the drop (`tx`). ```json { “addresses”: string[], “timestamp”: number, "balanceType": string, "threshold": number, “initialBalance”: GlacierPChainBalanceType, “finalBalance”: GlacierPChainBalanceType, “tx”: GlacierPChainTx } ``` *** # Validator Activity Source: https://developers.avacloud.io/webhooks-api/platform-webhooks-validator Tracks activities related to validators, identified by `NodeIDs` or `SubnetIDs`. ![Validator activity](https://mintlify.s3.us-west-1.amazonaws.com/avalabs-47ea3976/images/validator_activity.png) * **Sub-events:** * `validator_stake:` Triggered when a validator registers on a specified subnet or via a specific `NodeID`. * `delegator_stake:` Triggered when a delegator's staking transaction is confirmed, initiating their staking period with a validator. * `reward_distribution:`Triggered when a validator or delegator receives a reward, monitored by `NodeID` or `SubnetID`. * `l1_validator_balance_increased:`Triggered when an L1 validator’s balance increases via a specific transaction. * `l1_validator_disabled:`Triggered when an L1 validator is marked inactive (e.g., due to insufficient balance or a disable transaction). * `l1_validator_removed:`Triggered when an L1 validator is removed from the validator set. * `l1_validator_threshold_reached:`Triggered when an L1 validator’s balance falls below a specified threshold. You can subscribe to multiple sub-events in a single webhook, reducing the number of subscriptions you need to manage. **Understanding balance types** On the P and X chains, addresses can hold assets in various states, referred to as balance types. These are essential for configuring events like `BALANCE_THRESHOLD_PLATFORM`. Below is a summary: * `unlockedUnstaked:`Assets neither locked nor staked; immediately available for transactions. * `unlockedStaked:`Assets previously staked, now unlocked and available. * `lockedPlatform:`Unstaked assets locked at the platform level (not immediately usable). * `lockedStakeable:`Locked assets usable only for staking. * `lockedStaked:`Staked assets that remain locked post-staking period. * `pendingStaked:`Assets committed to staking, awaiting the staking period start. * `atomicMemoryUnlocked:`Unlocked assets in atomic memory (for cross-chain transfers). * `atomicMemoryLocked:`Locked assets in atomic memory. Understanding these types helps you set precise thresholds and interpret balance-related webhook data. For detailed definitions, refer to the [API documentation](https://developers.avacloud.io/data-api/primary-network-balances/get-balances#response-balances) *** ## What Data Will You Receive? When an event triggers your webhook, you’ll receive a JSON payload with details about the event. Here’s what to expect for each event: ### Validator Stake This event describes a validator `NodeID-Ns1eDN3K9HTnavgiBQhtpzRxUCxJ55Xhc` staking **2,700,000 AVAX** on the Avalanche primary network for approximately 31 days. The transaction processes previously unlocked funds, stakes the specified amount, and returns the remainder, with a small fee burned. The validator anticipates earning **13,481.66 AVAX** in rewards and has set a 5% delegation fee for potential delegators. This event strengthens the network’s security while rewarding the validator for its participation. ```json {3,7,24,30,32,35} [expandable] { "webhookId": "0c7367f9-27e8-4bb3-86a3-07bc4167674e", "eventType": "validator_activity", "messageId": "ca078039-c06a-482f-a40c-c3c094da9091", "event": { "eventType": "validator_stake", "subnetID": "11111111111111111111111111111111LpoYY", "nodeID": "NodeID-Ns1eDN3K9HTnavgiBQhtpzRxUCxJ55Xhc", "weight": "2700000000000000", "startTime": 1742852673, "endTime": 1745527591, "isL1": false, "l1ValidatorInfo": { "l1ValidationID": "", "subnetID": "", "nodeID": "", "initialPaygBalance": 0, "weight": 0, "remainingBalance": 0 }, "tx": { "txHash": "2Ruhz6fLF8wmYv7FoQ85KwkVeshJGUpczEWPa8xU62gZPrGuGV", "txType": "AddPermissionlessValidatorTx", "blockTimestamp": 1742852673, "blockNumber": "20995013", "blockHash": "69vELykyza4CVC7NihVN8zVSuGtesWb6Pr9pKp64qC78ZDhes", "memo": "0x", "rewardAddresses": [ "avax1hpx0u75s006t6w65yjp3u69y3qlfcxqfmrpzrd" ], "estimatedReward": "13481660440072", "startTimestamp": 1742852673, "endTimestamp": 1745527591, "delegationFeePercent": "50000", "nodeId": "NodeID-Ns1eDN3K9HTnavgiBQhtpzRxUCxJ55Xhc", "subnetId": "11111111111111111111111111111111LpoYY", "blsCredentials": { "publicKey": "0x9734f5914209be61c0f8f0fd673c299b15a91f039631be26d7d5d89bb4d144b43301345fb617d4f6d6bc9ac1a2326d6a", "proofOfPossession": "0xb86ce00fe21e896aedb81052e501e1696bf4b935581ddd33b8d5edc75e6fb25c99a16c084e153e67803c9d51f9c032460d160e1b4abff2d1b4e0d49182000980e5eb0c8b0bfcff9d157fc28f928ff4cdf41e542b9303f7d1f1b1746b7c1b28da" }, "consumedUtxos": [ { "addresses": [ "avax12s9rgr7v27h06tf0lnuzfel7808gpkalj5kf5w" ], "utxoId": "26Qikh53AwJWsH45itJEMnZBa1xAFPZhXU48jx7NixvA5H13L6", "txHash": "jJLzasvkYqm8Ri8G1HLtBZ3az6ZuevtYm6PMXBDjrRsqSzRHR", "outputIndex": 1, "blockTimestamp": 1740335435, "blockNumber": "20786051", "consumingTxHash": "2Ruhz6fLF8wmYv7FoQ85KwkVeshJGUpczEWPa8xU62gZPrGuGV", "consumingBlockTimestamp": 1742852673, "consumingBlockNumber": "20995013", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "2699999969229290" }, "utxoType": "TRANSFER", "amount": "2699999969229290", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": true, "utxoStartTimestamp": 1740335435, "utxoEndTimestamp": 1742754746 }, { "addresses": [ "avax12s9rgr7v27h06tf0lnuzfel7808gpkalj5kf5w" ], "utxoId": "2XRJ68fgkxzJHu72NeEMw4azjq9ytBkxY8BPwNywj6JCiyGAos", "txHash": "3XHJdjyhNAtV947zQMcLdGHDeoEo56BFq6AMuiyvHZfbG1m6w", "outputIndex": 1, "blockTimestamp": 1740335360, "blockNumber": "20786046", "consumingTxHash": "2Ruhz6fLF8wmYv7FoQ85KwkVeshJGUpczEWPa8xU62gZPrGuGV", "consumingBlockTimestamp": 1742852673, "consumingBlockNumber": "20995013", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "1350000000000000" }, "utxoType": "TRANSFER", "amount": "1350000000000000", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": true, "utxoStartTimestamp": 1740335360, "utxoEndTimestamp": 1742754669 } ], "emittedUtxos": [ { "addresses": [ "avax12s9rgr7v27h06tf0lnuzfel7808gpkalj5kf5w" ], "utxoId": "2K4DzA68MDdQZhpNXZa4mepUEoVVugE23TjnHAZnsMQLYQTaeB", "txHash": "2Ruhz6fLF8wmYv7FoQ85KwkVeshJGUpczEWPa8xU62gZPrGuGV", "outputIndex": 0, "blockTimestamp": 1742852673, "blockNumber": "20995013", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "1349999969212638" }, "utxoType": "TRANSFER", "amount": "1349999969212638", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": false }, { "addresses": [ "avax12s9rgr7v27h06tf0lnuzfel7808gpkalj5kf5w" ], "utxoId": "2TycNZUnmoEdN4hftNscohVnuwLUuj8ZujwxU7FnXVJoqRfGsG", "txHash": "2Ruhz6fLF8wmYv7FoQ85KwkVeshJGUpczEWPa8xU62gZPrGuGV", "outputIndex": 1, "blockTimestamp": 1742852673, "blockNumber": "20995013", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "2700000000000000" }, "utxoType": "TRANSFER", "amount": "2700000000000000", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": true, "utxoStartTimestamp": 1742852673, "utxoEndTimestamp": 1745527591 } ], "value": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "4049999969212638" } ], "amountBurned": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "16652" } ], "amountStaked": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "2700000000000000" } ], "amountL1ValidatorBalanceBurned": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "0" } ] } } } ``` ### Delegator Stake This example shows a delegator staking **184.507739834 AVAX** with the validator `NodeID-8mFFkAeyLkQ5Kgw85ZeAb5XFXjqsxPGUv` on the Avalanche Primary Network. The delegation, starting at timestamp `1742850281` and ending at `1744153333` (\~15 days), was processed through a permissionless delegation transaction. The delegator is expected to earn approximately **0.444953 AVAX** in rewards, which will be sent to `avax19zfygxaf59stehzedhxjesads0p5jdvfeedal0`. **Delegation:** * A delegator staked **184.507739834 AVAX** with the validator `NodeID-8mFFkAeyLkQ5Kgw85ZeAb5XFXjqsxPGUv` on the Avalanche Primary Network. * The staking period begins at Unix timestamp `1742850281` and ends at `1744153333`, lasting approximately **15.08 days**. * The estimated staking reward is **0.444953 AVAX**, to be sent to the address `avax19zfygxaf59stehzedhxjesads0p5jdvfeedal0`. **Transaction:** * Executed via transaction `DLwC2zX2oS5gwQ9yahpQNzprN4CFzvcDkG8YeYDxhSpeBvPsL` in block `20994783` at timestamp `1742850281`. * Consumed *\~362.2002 AVAX* from two UTXOs and emitted two new UTXOs: one for the staked amount (\~184.5077 AVAX) and one for the change (\~177.6924 AVAX). * A transaction fee of \~0.00001126 AVAX was burned. ```json {3,7,30,32,33,34,187} [expandable] { "webhookId": "0c7367f9-27e8-4bb3-86a3-07bc4167674e", "eventType": "validator_activity", "messageId": "12b3baf0-0144-41ed-85a0-7a3c52ef6cdb", "event": { "eventType": "delegator_stake", "subnetID": "11111111111111111111111111111111LpoYY", "nodeID": "NodeID-8mFFkAeyLkQ5Kgw85ZeAb5XFXjqsxPGUv", "weight": "184507739834", "startTime": 1742850281, "endTime": 1744153333, "isL1": false, "l1ValidatorInfo": { "l1ValidationID": "", "subnetID": "", "nodeID": "", "initialPaygBalance": 0, "weight": 0, "remainingBalance": 0 }, "tx": { "txHash": "DLwC2zX2oS5gwQ9yahpQNzprN4CFzvcDkG8YeYDxhSpeBvPsL", "txType": "AddPermissionlessDelegatorTx", "blockTimestamp": 1742850281, "blockNumber": "20994783", "blockHash": "2XMdLTnFD4A6z3UChwwKYeqvAjZa2HatvpsayVpcwtKdjFcMpa", "memo": "0x", "rewardAddresses": [ "avax19zfygxaf59stehzedhxjesads0p5jdvfeedal0" ], "estimatedReward": "444953000", "startTimestamp": 1742850281, "endTimestamp": 1744153333, "nodeId": "NodeID-8mFFkAeyLkQ5Kgw85ZeAb5XFXjqsxPGUv", "subnetId": "11111111111111111111111111111111LpoYY", "consumedUtxos": [ { "addresses": [ "avax1tnuesf6cqwnjw7fxjyk7lhch0vhf0v95wj5jvy" ], "utxoId": "2tFXbL5rURgb9KbkLZyBxGbHgWshmmtSsLpNFXXwXHSEkG4FMh", "txHash": "W7mXWuhFAao35i1yXaAZfW9fxqJBiFK1LXzi3CHbhhQwnun9Y", "outputIndex": 1, "blockTimestamp": 1741503909, "blockNumber": "20881177", "consumingTxHash": "DLwC2zX2oS5gwQ9yahpQNzprN4CFzvcDkG8YeYDxhSpeBvPsL", "consumingBlockTimestamp": 1742850281, "consumingBlockNumber": "20994783", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "179976464484" }, "utxoType": "TRANSFER", "amount": "179976464484", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": true, "utxoStartTimestamp": 1741503909, "utxoEndTimestamp": 1742850189 }, { "addresses": [ "avax1tnuesf6cqwnjw7fxjyk7lhch0vhf0v95wj5jvy" ], "utxoId": "2VjUo9HzdpfKpy97sXqw6btiiGPACP3tE7ojf6xeHGt6TxBXeL", "txHash": "2AkKtNwZrqGJV6dCzbujj8TuiZApKHoAcxionAL6ADbLGseih6", "outputIndex": 1, "blockTimestamp": 1741529804, "blockNumber": "20883523", "consumingTxHash": "DLwC2zX2oS5gwQ9yahpQNzprN4CFzvcDkG8YeYDxhSpeBvPsL", "consumingBlockTimestamp": 1742850281, "consumingBlockNumber": "20994783", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "182223698385" }, "utxoType": "TRANSFER", "amount": "182223698385", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": true, "utxoStartTimestamp": 1741529804, "utxoEndTimestamp": 1742850223 } ], "emittedUtxos": [ { "addresses": [ "avax1tnuesf6cqwnjw7fxjyk7lhch0vhf0v95wj5jvy" ], "utxoId": "nwS42MVaWhk4atPvbCLBp8ZsY4vrJwU3ZgtsBhEvtLdPdhP9A", "txHash": "DLwC2zX2oS5gwQ9yahpQNzprN4CFzvcDkG8YeYDxhSpeBvPsL", "outputIndex": 0, "blockTimestamp": 1742850281, "blockNumber": "20994783", "consumingTxHash": "m2q5WdtLxKThFEu6SFKXqUiPvYzmMEj13s7Xo6Jggf7A55HA2", "consumingBlockTimestamp": 1742850284, "consumingBlockNumber": "20994784", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "177692411775" }, "utxoType": "TRANSFER", "amount": "177692411775", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": false }, { "addresses": [ "avax1tnuesf6cqwnjw7fxjyk7lhch0vhf0v95wj5jvy" ], "utxoId": "p4kEKWoFPo8j3UZTbjsJN3tFCFXpgbhJvYqrAR6y4uUPwWtVY", "txHash": "DLwC2zX2oS5gwQ9yahpQNzprN4CFzvcDkG8YeYDxhSpeBvPsL", "outputIndex": 1, "blockTimestamp": 1742850281, "blockNumber": "20994783", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "184507739834" }, "utxoType": "TRANSFER", "amount": "184507739834", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": true, "utxoStartTimestamp": 1742850281, "utxoEndTimestamp": 1744153333 } ], "value": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "362200151609" } ], "amountBurned": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "11260" } ], "amountStaked": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "184507739834" } ], "amountL1ValidatorBalanceBurned": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "0" } ] } } } ``` *** ## Reward distribution ### Validator Reward Distribution This example shows a payload where the validator with `NodeID-ARXUBU2TCXBYG7JdCx7ntuPwBf73pHsTN` has received a staking reward of **4.836372611 AVAX** after staking **2009.726899312 AVAX** from `1741545923` to `1742841915`. The reward was distributed to the address `avax10f8305248c0wsfsdempdtpx7lpkc30vwzl9y9q` via the reward transaction `iK11FDhbLvNKwXXrzGXE1eQfdWQVHyqjkmh8wiii8DTTZ73nM`. **Reward Details** * **Reward Amount:** `4836372611` nanoAVAX \ Since AVAX has a denomination of 9 (1 AVAX = 10^9 nanoAVAX), this converts to **4.836372611 AVAX**. * **Reward Type:** `VALIDATOR` \ Indicates that this reward is for the validator’s staking activity. * **Reward Address:** `avax10f8305248c0wsfsdempdtpx7lpkc30vwzl9y9q` \ The address where the reward is sent. **Staking Period** * **Start Timestamp:** `1741545923` (Unix timestamp) \ Corresponds to the time the staking transaction was included in the blockchain, marking the start of the staking period. * **End Timestamp:** `1742841915` (Unix timestamp) \ Marks the end of the staking period, coinciding with the reward distribution. \\ * **Duration:** From `1741545923` to `1742841915`, approximately 15 days (1295992 seconds). ```json {3,7,13,14,52,57,61,62} [expandable] { "webhookId": "89266b1b-61a1-40f7-a309-59af999a048b", "eventType": "validator_activity", "messageId": "ee83d3ae-262e-4eb5-992e-6b398f756ef3", "event": { "eventType": "reward_distribution", "nodeID": "NodeID-ARXUBU2TCXBYG7JdCx7ntuPwBf73pHsTN", "subnetID": "11111111111111111111111111111111LpoYY", "rewardAddresses": [ "avax10f8305248c0wsfsdempdtpx7lpkc30vwzl9y9q" ], "amount": "4836372611", "rewardType": "VALIDATOR", "rewardTxHash": "iK11FDhbLvNKwXXrzGXE1eQfdWQVHyqjkmh8wiii8DTTZ73nM", "stakingTxHash": "AwDXauL61FLkaZia7a7vwJdXL8Lv7Bvu8TpfE3PhHYHZ1h3KT", "rewardTx": { "txHash": "iK11FDhbLvNKwXXrzGXE1eQfdWQVHyqjkmh8wiii8DTTZ73nM", "txType": "RewardValidatorTx", "blockTimestamp": 1742841915, "blockNumber": "20993987", "blockHash": "CwbgPKECAGhRYh9xu8GM1PRmNRfRWgVsBJss6YmGMFeMQVvXu", "memo": "", "stakingTxHash": "AwDXauL61FLkaZia7a7vwJdXL8Lv7Bvu8TpfE3PhHYHZ1h3KT", "rewardAddresses": [ "avax10f8305248c0wsfsdempdtpx7lpkc30vwzl9y9q" ], "nodeId": "NodeID-ARXUBU2TCXBYG7JdCx7ntuPwBf73pHsTN", "subnetId": "11111111111111111111111111111111LpoYY", "consumedUtxos": [ ], "emittedUtxos": [ ], "value": [ ], "amountBurned": [ ], "amountStaked": [ ], "amountL1ValidatorBalanceBurned": [ ] }, "stakingTx": { "txHash": "AwDXauL61FLkaZia7a7vwJdXL8Lv7Bvu8TpfE3PhHYHZ1h3KT", "txType": "AddPermissionlessValidatorTx", "blockTimestamp": 1741545923, "blockNumber": "20885184", "blockHash": "2NdapVdGtAZFDwruEiEsGihQZnRjesrodKdM3a41anrUsnQdfU", "memo": "0x", "rewardAddresses": [ "avax10f8305248c0wsfsdempdtpx7lpkc30vwzl9y9q" ], "rewardTxHash": "iK11FDhbLvNKwXXrzGXE1eQfdWQVHyqjkmh8wiii8DTTZ73nM", "estimatedReward": "4836372611", "startTimestamp": 1741545923, "endTimestamp": 1742841915, "delegationFeePercent": "20000", "nodeId": "NodeID-ARXUBU2TCXBYG7JdCx7ntuPwBf73pHsTN", "subnetId": "11111111111111111111111111111111LpoYY", "blsCredentials": { "publicKey": "0x98b62c058ecde88c860756dd4968434bc6240f70c5af18ed1f5026f82601f94228c4550581fd4196a69674e4b8dfe4be", "proofOfPossession": "0x96047f55349675ec0e95eaa53a40958f1421654d8cd785e9ca9fc5c3035a897899b362e12e8f03c936644a5e5f7d161a0576a99b064a82b73636f2bf1911e4a115cbc9fed5c5b8ffaf90496cdc11a25121bf077be9d921ee74d9858cd55d2602" }, "consumedUtxos": [ { "addresses": [ "avax10f8305248c0wsfsdempdtpx7lpkc30vwzl9y9q" ], "utxoId": "2PrK8TrzJYDjNfxpY6VRZZKqeLPByFXD2pLoa9rmc29uRwjkKP", "txHash": "2vFCqjStaE5JaxTixF15xrFnCLojxEgjzNYCYwS3dzGkAwaYPf", "outputIndex": 0, "blockTimestamp": 1741545875, "blockNumber": "20885170", "consumingTxHash": "AwDXauL61FLkaZia7a7vwJdXL8Lv7Bvu8TpfE3PhHYHZ1h3KT", "consumingBlockTimestamp": 1741545923, "consumingBlockNumber": "20885184", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "2009726891042" }, "utxoType": "TRANSFER", "amount": "2009726891042", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": false }, { "addresses": [ "avax10f8305248c0wsfsdempdtpx7lpkc30vwzl9y9q" ], "utxoId": "pUtaoF7X83NsvyMZQi6LtqpeuznGWEnTanqs5jhEcU5kFtuYs", "txHash": "2fnmPQQGwuiLGbeRdRDr5mNKFgFnQZzjutnvoBgJgCMnZiZFBK", "outputIndex": 2, "blockTimestamp": 1740249835, "blockNumber": "20776402", "consumingTxHash": "AwDXauL61FLkaZia7a7vwJdXL8Lv7Bvu8TpfE3PhHYHZ1h3KT", "consumingBlockTimestamp": 1741545923, "consumingBlockNumber": "20885184", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "1999999956266" }, "utxoType": "TRANSFER", "amount": "1999999956266", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": true, "utxoStartTimestamp": 1740249835, "utxoEndTimestamp": 1741545831 } ], "emittedUtxos": [ { "addresses": [ "avax10f8305248c0wsfsdempdtpx7lpkc30vwzl9y9q" ], "utxoId": "2nY9g35whvatF1KcUi9AsjWtPhaotuUvLKAZzU48s3aCU5fHhR", "txHash": "AwDXauL61FLkaZia7a7vwJdXL8Lv7Bvu8TpfE3PhHYHZ1h3KT", "outputIndex": 0, "blockTimestamp": 1741545923, "blockNumber": "20885184", "consumingTxHash": "znJoB1bt4thuEaKaXN1V1z6Vy4gPPCaHP8FqmGR6MN1wNwU8F", "consumingBlockTimestamp": 1741546078, "consumingBlockNumber": "20885194", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "1999999912532" }, "utxoType": "TRANSFER", "amount": "1999999912532", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": false }, { "addresses": [ "avax10f8305248c0wsfsdempdtpx7lpkc30vwzl9y9q" ], "utxoId": "hzjzv2XnyAo5kQpUzwZGfZQFhdsp5TjDBrUGDg85kR5pk8pJ4", "txHash": "AwDXauL61FLkaZia7a7vwJdXL8Lv7Bvu8TpfE3PhHYHZ1h3KT", "outputIndex": 1, "blockTimestamp": 1741545923, "blockNumber": "20885184", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "43734" }, "utxoType": "TRANSFER", "amount": "43734", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": true, "utxoStartTimestamp": 1741545923, "utxoEndTimestamp": 1742841915 }, { "addresses": [ "avax10f8305248c0wsfsdempdtpx7lpkc30vwzl9y9q" ], "utxoId": "2MuasJwJtT7eJHa34d2Vv3WhAMMZtmsMpQdP3NzxpFQwHWPKUo", "txHash": "AwDXauL61FLkaZia7a7vwJdXL8Lv7Bvu8TpfE3PhHYHZ1h3KT", "outputIndex": 2, "blockTimestamp": 1741545923, "blockNumber": "20885184", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "2009726855578" }, "utxoType": "TRANSFER", "amount": "2009726855578", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": true, "utxoStartTimestamp": 1741545923, "utxoEndTimestamp": 1742841915 }, { "addresses": [ "avax10f8305248c0wsfsdempdtpx7lpkc30vwzl9y9q" ], "utxoId": "kmmwg1EhQrjmoktSAi7g37ohB5ti8gYiXCyXN4p8LtSbwAffy", "txHash": "AwDXauL61FLkaZia7a7vwJdXL8Lv7Bvu8TpfE3PhHYHZ1h3KT", "outputIndex": 3, "blockTimestamp": 1742841915, "blockNumber": "20993987", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "4836372611" }, "utxoType": "TRANSFER", "amount": "4836372611", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": false, "rewardType": "VALIDATOR" } ], "value": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "4014563184455" } ], "amountBurned": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "35464" } ], "amountStaked": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "2009726899312" } ], "amountL1ValidatorBalanceBurned": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "0" } ] } } } ``` ### Delegator Reward Distribution This example shows a payload where a delegator received a reward of **0.467719668 AVAX** for delegating **197.312156887 AVAX** to the validator `NodeID-5ZXpg581dpjG8AdoJgTDeXXLnxrQc9Wtd` on the Avalanche Primary Network. The delegation lasted approximately 15 days, from `1741539323` to `1742841909`. The reward, slightly less than the estimated **0.477264968 AVAX**, was successfully distributed to `avax19zfygxaf59stehzedhxjesads0p5jdvfeedal0`. Summary of the Event **Delegation:** * On timestamp `1741539323` (block `20884474`), the delegator staked **197.312156887 AVAX** with the validator `NodeID-5ZXpg581dpjG8AdoJgTDeXXLnxrQc9Wtd` via transaction `22TKPMsMFb3Z8Dpk89FnLjA5HnCvSDj9VLQjuyqm4jmNX6W8R4`. * The staking period was set to end at 1742841909 (\~15 days later), with an estimated reward of 0.477264968 AVAX. **Reward Distribution:** * On timestamp `1742841909` (block `20993983`), the staking period concluded, and transaction `nhgqAsJQsFcTEwsqMWktwfF1SPbp1488LYZvYSWt9WTjzSnSC` distributed a reward of **0.467719668 AVAX** to the address `avax19zfygxaf59stehzedhxjesads0p5jdvfeedal0`. ```json {3,7,8,11,13,16,19,26,240} [expandable] { "webhookId": "89266b1b-61a1-40f7-a309-59af999a048b", "eventType": "validator_activity", "messageId": "bf85a5fc-7bb9-4e23-987e-10ec8c563921", "event": { "eventType": "reward_distribution", "nodeID": "NodeID-5ZXpg581dpjG8AdoJgTDeXXLnxrQc9Wtd", "subnetID": "11111111111111111111111111111111LpoYY", "rewardAddresses": [ "avax19zfygxaf59stehzedhxjesads0p5jdvfeedal0" ], "amount": "467719668", "rewardType": "DELEGATOR", "rewardTxHash": "nhgqAsJQsFcTEwsqMWktwfF1SPbp1488LYZvYSWt9WTjzSnSC", "stakingTxHash": "22TKPMsMFb3Z8Dpk89FnLjA5HnCvSDj9VLQjuyqm4jmNX6W8R4", "rewardTx": { "txHash": "nhgqAsJQsFcTEwsqMWktwfF1SPbp1488LYZvYSWt9WTjzSnSC", "txType": "RewardValidatorTx", "blockTimestamp": 1742841909, "blockNumber": "20993983", "blockHash": "2vZ7GbPAQ27oS4V4evwjgFWfpxL3khWatK6ty2ZYZzN3zTzbCa", "memo": "", "stakingTxHash": "22TKPMsMFb3Z8Dpk89FnLjA5HnCvSDj9VLQjuyqm4jmNX6W8R4", "rewardAddresses": [ "avax19zfygxaf59stehzedhxjesads0p5jdvfeedal0" ], "nodeId": "NodeID-5ZXpg581dpjG8AdoJgTDeXXLnxrQc9Wtd", "subnetId": "11111111111111111111111111111111LpoYY", "consumedUtxos": [ ], "emittedUtxos": [ ], "value": [ ], "amountBurned": [ ], "amountStaked": [ ], "amountL1ValidatorBalanceBurned": [ ] }, "stakingTx": { "txHash": "22TKPMsMFb3Z8Dpk89FnLjA5HnCvSDj9VLQjuyqm4jmNX6W8R4", "txType": "AddPermissionlessDelegatorTx", "blockTimestamp": 1741539323, "blockNumber": "20884474", "blockHash": "2Dmf7kGgitoyMU8rabHkRTKjQ3AGYEgRETr6VDcFHCRz9GoTYq", "memo": "0x", "rewardAddresses": [ "avax19zfygxaf59stehzedhxjesads0p5jdvfeedal0" ], "rewardTxHash": "nhgqAsJQsFcTEwsqMWktwfF1SPbp1488LYZvYSWt9WTjzSnSC", "estimatedReward": "477264968", "startTimestamp": 1741539323, "endTimestamp": 1742841909, "nodeId": "NodeID-5ZXpg581dpjG8AdoJgTDeXXLnxrQc9Wtd", "subnetId": "11111111111111111111111111111111LpoYY", "consumedUtxos": [ { "addresses": [ "avax1tnuesf6cqwnjw7fxjyk7lhch0vhf0v95wj5jvy" ], "utxoId": "SYnrnbZNQVy5w3QQ4mRrW9UUF9Ph6begM9jFpBbykfVVARCwG", "txHash": "2pGucKd7rVXR1S7pVi9c8F1nMTdgsNupNtvDaJ8bvmNNinybRB", "outputIndex": 0, "blockTimestamp": 1741539320, "blockNumber": "20884473", "consumingTxHash": "22TKPMsMFb3Z8Dpk89FnLjA5HnCvSDj9VLQjuyqm4jmNX6W8R4", "consumingBlockTimestamp": 1741539323, "consumingBlockNumber": "20884474", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "186653818832" }, "utxoType": "TRANSFER", "amount": "186653818832", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": false }, { "addresses": [ "avax1tnuesf6cqwnjw7fxjyk7lhch0vhf0v95wj5jvy" ], "utxoId": "XGuHtbHK3DcX24TVbJpAcyuWHatHRz12tEDP5Ep7YWVsHkLdd", "txHash": "2p1WkF9TD7CzL7EFc65zEWRLa1Z9zb7a8uBvgq3WGtX7x7GEkW", "outputIndex": 1, "blockTimestamp": 1740295319, "blockNumber": "20781422", "consumingTxHash": "22TKPMsMFb3Z8Dpk89FnLjA5HnCvSDj9VLQjuyqm4jmNX6W8R4", "consumingBlockTimestamp": 1741539323, "consumingBlockNumber": "20884474", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "181067881452" }, "utxoType": "TRANSFER", "amount": "181067881452", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": true, "utxoStartTimestamp": 1740295319, "utxoEndTimestamp": 1741539293 } ], "emittedUtxos": [ { "addresses": [ "avax1tnuesf6cqwnjw7fxjyk7lhch0vhf0v95wj5jvy" ], "utxoId": "2StywFfLwxF6s58iMMMwUgTMahJHMbbesWKrGQhLKzoqXnKcdy", "txHash": "22TKPMsMFb3Z8Dpk89FnLjA5HnCvSDj9VLQjuyqm4jmNX6W8R4", "outputIndex": 0, "blockTimestamp": 1741539323, "blockNumber": "20884474", "consumingTxHash": "5ofPac4hfrUQzEpkoiDJTovnSTLMGgrYaJf9pXQQm5RatkkMU", "consumingBlockTimestamp": 1741539325, "consumingBlockNumber": "20884475", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "170409532137" }, "utxoType": "TRANSFER", "amount": "170409532137", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": false }, { "addresses": [ "avax1tnuesf6cqwnjw7fxjyk7lhch0vhf0v95wj5jvy" ], "utxoId": "snY2UStt22Gywciqpg96Pwf7YNpmf24FvVfahWXfeRM6iinMg", "txHash": "22TKPMsMFb3Z8Dpk89FnLjA5HnCvSDj9VLQjuyqm4jmNX6W8R4", "outputIndex": 1, "blockTimestamp": 1741539323, "blockNumber": "20884474", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "197312156887" }, "utxoType": "TRANSFER", "amount": "197312156887", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": true, "utxoStartTimestamp": 1741539323, "utxoEndTimestamp": 1742841909 }, { "addresses": [ "avax19zfygxaf59stehzedhxjesads0p5jdvfeedal0" ], "utxoId": "22hm545i9XEUjob6RKCoG7jcwEuWgiaLKXu5ktZHvqqEyzPW6y", "txHash": "22TKPMsMFb3Z8Dpk89FnLjA5HnCvSDj9VLQjuyqm4jmNX6W8R4", "outputIndex": 2, "blockTimestamp": 1742841909, "blockNumber": "20993983", "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "asset": { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "467719668" }, "utxoType": "TRANSFER", "amount": "467719668", "platformLocktime": 0, "threshold": 1, "createdOnChainId": "11111111111111111111111111111111LpoYY", "consumedOnChainId": "11111111111111111111111111111111LpoYY", "staked": false, "rewardType": "DELEGATOR" } ], "value": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "368189408692" } ], "amountBurned": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "11260" } ], "amountStaked": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "197312156887" } ], "amountL1ValidatorBalanceBurned": [ { "assetId": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z", "name": "Avalanche", "symbol": "AVAX", "denomination": 9, "type": "secp256k1", "amount": "0" } ] } } } ``` *** ## L1 Validator Balance Increased The `l1_validator_balance_increased` event happens when an L1 validator gets more balance added to its account. Think of it like depositing money into a bank account so the validator can keep working. A special transaction (called `IncreaseL1BValidatorBalanceTx`) is used to give the validator more resources. **Details it includes:** * When it happened (`timestamp`). * Which validator got the boost (`nodeId`). * Which network it’s part of (`subnetId`). * How much balance was added (`balanceIncrease`). * Info about the validator (`l1ValidatorInfo`) and the transaction itself (`tx`). ```json { “timestamp”: number, "nodeId": string, "subnetId": string, "balanceIncrease": string, "l1ValidatorInfo": GlacierL1ValidatorInfoType, “tx”: GlacierPChainTx } ``` *** ## L1 Validator Disabled The `l1_validator_balance_disabled` event will be triggered whenever a relevant L1 validator is marked as inactive, either due to insufficient validator balance or when a `DisableL1Validatator` transaction is issued. The `disableType` property will indicate whether the validator is disabled to low balance or `DisableL1ValidatorTx`. **Details it includes:** * When it happened (`timestamp`). * Which validator was disabled (`nodeId`). * Which network it’s part of (`subnetId`). * Why it was disabled (disableType: either `low_balance` or `disable_tx_issued`). * Info about the validator (`l1ValidatorInfo`) and the transaction, if any (`tx`). ```json { “timestamp”: number, "nodeId": string, "subnetId": string, "disableType": "low_balance" | "disable_tx_issued", "l1ValidatorInfo": GlacierL1ValidatorInfoType, “tx”: GlacierPChainTx } ``` *** ## L1 Validator Removed The `l1_validator_removed` event will be triggered whenever an L1 validator is completely removed from the L1’s validator set. This generally happens when the `SetL1ValidatorWeight` transaction is issued with a final weight set as 0. **Details it includes:** * When it happened (`timestamp`). * Which validator was removed (`nodeId`). * Which network it’s part of (`subnetId`). * Why it was disabled (`disableType`: either `low_balance` or `disable_tx_issued`). * Info about the validator (`l1ValidatorInfo`) and the transaction (`tx`). ```json { “timestamp”: number, "nodeId": string, "subnetId": string, "disableType": "low_balance" | "disable_tx_issued", "l1ValidatorInfo": GlacierL1ValidatorInfoType, “tx”: GlacierPChainTx } ``` *** ## L1 Validator Threshold Reached The `l1_validator_balance_threshold_reached` event This event warns that a validator’s balance has dropped below a certain level (a "threshold"). It’s a heads-up that the validator might stop working soon if it doesn’t get more resources. The balance decreases gradually over time (like a subscription fee), and no specific transaction causes this. **Details it includes:** * When it happened (`timestamp`). * Which validator is low on balance (`nodeId`). * Which network it’s part of (`subnetId`). * What the balance was before (`previousPaygBalance`) and what it is now (`currentPaygBalance`). * Info about the validator (`l1ValidatorInfo`). ```json { “timestamp”: number, "nodeId": string, "subnetId": string, "previousPaygBalance": string, "currentPaygBalance": string, "l1ValidatorInfo": GlacierL1ValidatorInfoType, } ``` # Send Push notification Source: https://developers.avacloud.io/webhooks-api/push-notifications In this tutorial, we'll explore how to send push notifications to a user's wallet whenever they receive a transaction containing tokens. It's a handy way to keep users informed about their account activity. Note: This hypothetical example is not for real-world production use. We're simplifying things here for demonstration purposes, so there's no thorough error handling. We'll be using [OneSignal](https://onesignal.com) for sending push notifications, but you can also achieve similar functionality with other services like [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging) or [AWS Pinpoint](https://aws.amazon.com/pinpoint/). Now, let's dive into the details! ### Step 1 - OneSignal Setup The first step is to create a free account in [OneSignal](https://onesignal.com). For this example, we are going to use Web push but it works similarly for mobile. To get started, the first step is to create a free account on OneSignal. Once you've signed up and logged in, we'll proceed to create a new OneSignal App. For this example, we'll focus on using Web push notifications, but keep in mind that the process is quite similar for mobile apps. Create a new OneSignal App and select Web. Once your app is created, you'll be provided with an App ID and API Key. Keep these credentials handy as we'll need them later to integrate OneSignal with our code. Next, click on Configure Your Platform and select Web, select Code Custom, and set the site URL `http://localhost:3000` and enable both toggles for local development. This will generate a code snippet to add to your code. Download the OneSignal SDK files and copy them to the top-level root of your directory. ### Step 2 - Frontend Setup In a real-world scenario, your architecture typically involves customers signing up for subscriptions within your Web or Mobile App. To ensure these notifications are sent out, your app needs to register with a push notification provider such as OneSignal. To maintain privacy and security, we'll be using a hash of the wallet address as the `externalID` instead of directly sharing the addresses with OneSignal. This `externalID` will then be mapped to an address in our database. So, when our backend receives a webhook for a specific address, it can retrieve the corresponding `externalID` and send a push notification accordingly. ![OneSignal Architecture](https://mintlify.s3.us-west-1.amazonaws.com/avalabs-47ea3976/images/onesignal-architecture.png) For the sake of simplicity in our demonstration, we'll present a basic scenario where our frontend app retrieves the wallet address and registers it with OneSignal. Additionally, we'll simulate a database using an array within the code. Download the [sample code](https://github.com/javiertc/webhookdemo) and you'll see `client/inde.html` with this content. ```html

Avalanche push notifications

``` Run the project using Nodejs. ```bash npm install express axios path body-parser dotenv node app.js ``` Open a Chrome tab and type `http://localhost:3000`, you should see something like this. Then click on Connect and accept receiving push notifications. If you are using MacOS, check in **System Settings** > **Notifications** that you have enabled notifications for the browser. If everything runs correctly your browser should be registered in OneSignal. To check go to **Audience** > **Subscriptions** and verify that your browser is registered. ### Step 3 - Backend Setup Now, let's configure the backend to manage webhook events and dispatch notifications based on the incoming data. Here's the step-by-step process: 1. **Transaction Initiation:** When someone starts a transaction with your wallet as the destination, the webhooks detect the transaction and generate an event. 2. **Event Triggering:** The backend receives the event triggered by the transaction, containing the destination address. 3. **ExternalID Retrieval:** Using the received address, the backend retrieves the corresponding `externalID` associated with that wallet. 4. **Notification Dispatch:** The final step involves sending a notification through OneSignal, utilizing the retrieved `externalID`. ![OneSignal Backend](https://mintlify.s3.us-west-1.amazonaws.com/avalabs-47ea3976/images/onesignal-backend.png) #### 3.1 - Use Ngrok to tunnel the traffic to localhost If we want to test the webhook in our computer and we are behind a proxy/NAT device or a firewall we need a tool like Ngrok. Glacier will trigger the webhook and make a POST to the Ngrok cloud, then the request is forwarded to your local Ngrok client who in turn forwards it to the Node.js app listening on port 3000. Go to [https://ngrok.com/](https://ngrok.com/) create a free account, download the binary, and connect to your account. Create a Node.js app with Express and paste the following code to receive the webhook: To start an HTTP tunnel forwarding to your local port 3000 with Ngrok, run this next: ```bash ./ngrok http 3000 ``` You should see something like this: ``` ngrok (Ctrl+C to quit) Take our ngrok in production survey! https://forms.gle/aXiBFWzEA36DudFn6 Session Status online Account javier.toledo@avalabs.org (Plan: Free) Version 3.8.0 Region United States (us) Latency 48ms Web Interface http://127.0.0.1:4040 Forwarding https://c902-2600-1700-5220-11a0-813c-d5ac-d72c-f7fd.ngrok-free.app -> http://localhost:3000 Connections ttl opn rt1 rt5 p50 p90 33 0 0.00 0.00 5.02 5.05 HTTP Requests ------------- ``` #### 3.2 - Create the webhook The webhook can be created using the [Avacloud Dashboard](https://app.avacloud.io/) or Glacier API. For convenience, we are going to use cURL. For that copy the forwarding URL generated by Ngrok and append the `/callbackpath` and our address. ```bash curl --location 'https://glacier-api-dev.avax.network/v1/webhooks' \ --header 'x-glacier-api-key: ' \ --header 'Content-Type: application/json' \ --data '{ "url": " https://c902-2600-1700-5220-11a0-813c-d5ac-d72c-f7fd.ngrok-free.app/callback", "chainId": "43113", "eventType": "address_activity", "includeInternalTxs": true, "includeLogs": true, "metadata": { "addresses": ["0x8ae323046633A07FB162043f28Cea39FFc23B50A"] }, "name": "My wallet", "description": "My wallet" }' ``` Don't forget to add your API Key. If you don't have one go to the [Avacloud Dashboard](https://app.avacloud.io/) and create a new one. #### 3.3 - The backend To run the backend we need to add the environment variables in the root of your project. For that create an `.env` file with the following values: ``` PORT=3000 ONESIGNAL_API_KEY= APP_ID= ``` To get the APP ID from OneSignal go to **Settings** > **Keys and IDs** Since we are simulating the connection to a database to retrieve the externalID, we need to add the wallet address and the OneSignal externalID to the myDB array. ```javascript //simulating a DB const myDB = [ { name: 'wallet1', address: '0x8ae323046633A07FB162043f28Cea39FFc23B50A', externalID: '9c96e91d40c7a44c763fb55960e12293afbcfaf6228860550b0c1cc09cd40ac3' }, { name: 'wallet2', address: '0x1f83eC80D755A87B31553f670070bFD897c40CE0', externalID: '0xd39d39c99305c6df2446d5cc3d584dc1eb041d95ac8fb35d4246f1d2176bf330' } ]; ``` The code handles a webhook event triggered when a wallet receives a transaction, performs a lookup in the simulated "database" using the receiving address to retrieve the corresponding OneSignal `externalID`, and then sends an instruction to OneSignal to dispatch a notification to the browser, with OneSignal ultimately delivering the web push notification to the browser. ```javascript require('dotenv').config(); const axios = require('axios'); const express = require('express'); const bodyParser = require('body-parser'); const path = require('path'); const app = express(); const port = process.env.PORT || 3000; // Serve static website app.use(bodyParser.json()); app.use(express.static(path.join(__dirname, './client'))); //simulating a DB const myDB = [ { name: 'wallet1', address: '0x8ae323046633A07FB162043f28Cea39FFc23B50A', externalID: '9c96e91d40c7a44c763fb55960e12293afbcfaf6228860550b0c1cc09cd40ac3' }, { name: 'wallet2', address: '0x1f83eC80D755A87B31553f670070bFD897c40CE0', externalID: '0xd39d39c99305c6df2446d5cc3d584dc1eb041d95ac8fb35d4246f1d2176bf330' } ]; app.post('/callback', async (req, res) => { const { body } = req; try { res.sendStatus(200); handleTransaction(body.event.transaction).catch(error => { console.error('Error processing transaction:', error); }); } catch (error) { console.error('Error processing transaction:', error); res.status(500).json({ error: 'Internal server error' }); } }); // Handle transaction async function handleTransaction(transaction) { console.log('*****Transaction:', transaction); const notifications = []; const erc20Transfers = transaction?.erc20Transfers || []; for (const transfer of erc20Transfers) { const externalID = await getExternalID(transfer.to); const { symbol, valueWithDecimals } = transfer.erc20Token; notifications.push({ type: transfer.type, sender: transfer.from, receiver: transfer.to, amount: valueWithDecimals, token: symbol, externalID }); } if (transaction?.networkToken) { const { tokenSymbol, valueWithDecimals } = transaction.networkToken; const externalID = await getExternalID(transaction.to); notifications.push({ sender: transaction.from, receiver: transaction.to, amount: valueWithDecimals, token: tokenSymbol, externalID }); } if (notifications.length > 0) { sendNotifications(notifications); } } //connect to DB and return externalID async function getExternalID(address) { const entry = myDB.find(entry => entry.address.toLowerCase() === address.toLowerCase()); return entry ? entry.externalID : null; } // Send notifications async function sendNotifications(notifications) { for (const notification of notifications) { try { const data = { include_aliases: { external_id: [notification.externalID.toLowerCase()] }, target_channel: 'push', isAnyWeb: true, contents: { en: `You've received ${notification.amount} ${notification.token}` }, headings: { en: 'Core wallet' }, name: 'Notification', app_id: process.env.APP_ID }; console.log('data:', data); const response = await axios.post('https://onesignal.com/api/v1/notifications', data, { headers: { Authorization: `Bearer ${process.env.ONESIGNAL_API_KEY}`, 'Content-Type': 'application/json' } }); console.log('Notification sent:', response.data); } catch (error) { console.error('Error sending notification:', error); // Optionally, implement retry logic here } } } // Start the server app.listen(port, () => { console.log(`App listening at http://localhost:${port}`); }); ``` You can now start your backend server by running: ```Shell node app.js ``` Send AVAX from another wallet to the wallet being monitored by the webhook and you should receive a notification with the amount of Avax received. You can try it with any other ERC20 token as well. ### Conclusion In this tutorial, we've set up a frontend to connect to the Core wallet and enable push notifications using OneSignal. We've also implemented a backend to handle webhook events and send notifications based on the received data. By integrating the frontend with the backend, users can receive real-time notifications for blockchain events. # Rate Limits Source: https://developers.avacloud.io/webhooks-api/rate-limits Rate limiting is managed through a weighted scoring system, known as Compute Units (CUs). Each API request consumes a specified number of CUs, determined by the complexity of the request. This system is designed to accommodate basic requests while efficiently handling more computationally intensive operations. ## Rate Limit Tiers The maximum CUs (rate-limiting score) for a user depends on their subscription level and is delineated in the following table: | Subscription Level | Per Minute Limit (CUs) | Per Day Limit (CUs) | | :----------------- | :--------------------- | :------------------ | | Unauthenticated | 6,000 | 1,200,000 | | Free | 8,000 | 2,000,000 | | Base | 10,000 | 3,750,000 | | Growth | 14,000 | 11,200,000 | | Pro | 20,000 | 25,000,000 | To update your subscription level use the [AvaCloud Portal](https://app.avacloud.io/) Note: Rate limits apply collectively across both Webhooks and Data APIs, with usage from each counting toward your total CU limit. ## Rate Limit Categories The CUs for each category are defined in the following table: {/* webhooks weights value table start */} | Weight | CU Value | | :----- | :------- | | Free | 1 | | Small | 10 | | Medium | 20 | | Large | 50 | | XL | 100 | | XXL | 200 | {/* webhooks weights value table end */} ## Rate Limits for Webhook Endpoints The CUs for each route are defined in the table below: {/* webhooks execution weights table start */} | Endpoint | Method | Weight | CU Value | | :------------------------------------------ | :----- | :----- | :------- | | `/v1/webhooks` | POST | Medium | 20 | | `/v1/webhooks` | GET | Small | 10 | | `/v1/webhooks/{id}` | GET | Small | 10 | | `/v1/webhooks/{id}` | DELETE | Medium | 20 | | `/v1/webhooks/{id}` | PATCH | Medium | 20 | | `/v1/webhooks:generateOrRotateSharedSecret` | POST | Medium | 20 | | `/v1/webhooks:getSharedSecret` | GET | Small | 10 | | `/v1/webhooks/{id}/addresses` | PATCH | Medium | 20 | | `/v1/webhooks/{id}/addresses` | DELETE | Medium | 20 | | `/v1/webhooks/{id}/addresses` | GET | Medium | 20 | {/* webhooks execution weights table end */} All rate limits, weights, and CU values are subject to change. # Retry mechanism Source: https://developers.avacloud.io/webhooks-api/retries Our webhook system is designed to ensure you receive all your messages, even if temporary issues prevent immediate delivery. To achieve this, we’ve implemented a retry mechanism that resends messages if they don’t get through on the first attempt. Importantly, **retries are handled on a per-message basis**, meaning each webhook message follows its own independent retry schedule. This ensures that the failure of one message doesn’t affect the delivery attempts of others. This guide will walk you through how the retry mechanism works, the differences between free and paid tier users, and practical steps you can take to ensure your system handles webhooks effectively. ## How it works When we send a webhook message to your server, we expect a `200` status code within 10 seconds to confirm successful receipt. Your server should return this response immediately and process the message afterward. Processing the message before sending the response can lead to timeouts and trigger unnecessary retries. ![webhooks](https://mintlify.s3.us-west-1.amazonaws.com/avalabs-47ea3976/images/retries.png) * **Attempt 1:** We send the message expecting a respose with `200` status code. If we do not receive a `200` status code within **10 seconds**, the attempt is considered failed. During this window, any non-`2xx` responses are ignored. * **Attempt 2:** Occurs **10 seconds** after the first attempt, with another 10-second timeout and the same rule for ignoring non-`2xx` responses. * **Retry Queue After Two Failed Attempts** If both initial attempts fail, the message enters a **retry queue** with progressively longer intervals between attempts. Each retry attempt still has a 10-second timeout, and non-`2xx` responses are ignored during this window. The retry schedule is as follows: | Attempt | Interval | | ------- | -------- | | 3 | 1 min | | 4 | 5 min | | 5 | 10 min | | 6 | 30 min | | 7 | 2 hours | | 8 | 6 hours | | 9 | 12 hours | | 10 | 24 hours | **Total Retry Duration:** Up to approximately 44.8 hours (2,688 minutes) if all retries are exhausted. **Interval Timing:** Each retry interval starts 10 seconds after the previous attempt is deemed failed. For example, if attempt 2 fails at t=20 seconds, attempt 3 will start at t=80 seconds (20s + 1 minute interval + 10s). Since retries are per message, multiple messages can be in different stages of their retry schedules simultaneously without interfering with each other. ## Differences Between Free and Paid Tier Users The behavior of the retry mechanism varies based on your subscription tier: **Free tier users** * **Initial attempts limit:** If six messages fail both the first and second attempts, your webhook will be automatically deactivated. * **Retry queue limit:** Only five messages can enter the retry queue over the lifetime of the subscription. If a sixth message requires retry queuing, or if any message fails all 10 retry attempts, the subscription will be deactivated. **Paid tier users** * For paid users, webhooks will be deactivated if a single message, retried at the 24-hour interval, fails to process successfully. ## What you can do **Ensure server availability:** * Keep your server running smoothly to receive webhook messages without interruption. * Implement logging for incoming webhook requests and your server's responses to help identify any issues quickly. **Design for idempotency** * Set up your webhook handler so it can safely process the same message multiple times without causing errors or unwanted effects. This way, if retries occur, they won't negatively impact your system. * The webhook retry mechanism is designed to maximize the reliability of message delivery while minimizing the impact of temporary issues. By understanding how retries work—especially the per-message nature of the system—and following best practices like ensuring server availability and designing for idempotency, you can ensure a seamless experience with webhooks. ## Key Takeaways * Each message has its own retry schedule, ensuring isolation and reliability. * Free tier users have limits on failed attempts and retry queue entries, while paid users do not. * Implement logging and idempotency to handle retries effectively and avoid disruptions. * By following this guide, you’ll be well-equipped to manage webhooks and ensure your system remains robust, even in the face of temporary challenges. # Webhook Signature Source: https://developers.avacloud.io/webhooks-api/signature To make your webhooks extra secure, you can verify that they originated from our side by generating an HMAC SHA-256 hash code using your Authentication Token and request body. You can get the signing secret through the AvaCloud portal or Glacier API. ### Find your signing secret **Using the portal**\ Navigate to the webhook section and click on Generate Signing Secret. Create the secret and copy it to your code. **Using Glacier API**\ The following endpoint retrieves a shared secret: ```bash curl --location 'https://glacier-api.avax.network/v1/webhooks:getSharedSecret' \ --header 'x-glacier-api-key: ' \ ``` ### Validate the signature received Every outbound request will include an authentication signature in the header. This signature is generated by: 1. **Canonicalizing the JSON Payload**: This means arranging the JSON data in a standard format. 2. **Generating a Hash**: Using the HMAC SHA256 hash algorithm to create a hash of the canonicalized JSON payload. To verify that the signature is from us, follow these steps: 1. Generate the HMAC SHA256 hash of the received JSON payload. 2. Compare this generated hash with the signature in the request header. This process, known as verifying the digital signature, ensures the authenticity and integrity of the request. **Example Request Header** ``` Content-Type: application/json; x-signature: your-hashed-signature ``` ### Example Signature Validation Function This Node.js code sets up an HTTP server using the Express framework. It listens for POST requests sent to the `/callback` endpoint. Upon receiving a request, it validates the signature of the request against a predefined `signingSecret`. If the signature is valid, it logs match; otherwise, it logs no match. The server responds with a JSON object indicating that the request was received. ```JavaScript Node const express = require('express'); const crypto = require('crypto'); const { canonicalize } = require('json-canonicalize'); const app = express(); app.use(express.json({limit: '50mb'})); const signingSecret = 'c13cc017c4ed63bcc842c8edfb49df37512280326a32826de3b885340b8a3d53'; function isValidSignature(signingSecret, signature, payload) { const canonicalizedPayload = canonicalize(payload); const hmac = crypto.createHmac('sha256', Buffer.from(signingSecret, 'hex')); const digest = hmac.update(canonicalizedPayload).digest('base64'); console.log("signature: ", signature); console.log("digest", digest); return signature === digest; } app.post('/callback', express.json({ type: 'application/json' }), (request, response) => { const { body, headers } = request; const signature = headers['x-signature']; // Handle the event switch (body.evenType) { case 'address_activity': console.log("*** Address_activity ***"); console.log(body); if (isValidSignature(signingSecret, signature, body)) { console.log("match"); } else { console.log("no match"); } break; // ... handle other event types default: console.log(`Unhandled event type ${body}`); } // Return a response to acknowledge receipt of the event response.json({ received: true }); }); const PORT = 8000; app.listen(PORT, () => console.log(`Running on port ${PORT}`)); ``` ```python Python from flask import Flask, request, jsonify import hmac import hashlib import base64 import json app = Flask(__name__) SIGNING_SECRET = 'c13cc017c4ed63bcc842c8edfb49df37512280326a32826de3b885340b8a3d53' def canonicalize(payload): """Function to canonicalize JSON payload""" # In Python, canonicalization can be achieved by using sort_keys=True in json.dumps return json.dumps(payload, separators=(',', ':'), sort_keys=True) def is_valid_signature(signing_secret, signature, payload): canonicalized_payload = canonicalize(payload) hmac_obj = hmac.new(bytes.fromhex(signing_secret), canonicalized_payload.encode('utf-8'), hashlib.sha256) digest = base64.b64encode(hmac_obj.digest()).decode('utf-8') print("signature:", signature) print("digest:", digest) return signature == digest @app.route('/callback', methods=['POST']) def callback_handler(): body = request.json signature = request.headers.get('x-signature') # Handle the event if body.get('eventType') == 'address_activity': print("*** Address_activity ***") print(body) if is_valid_signature(SIGNING_SECRET, signature, body): print("match") else: print("no match") else: print(f"Unhandled event type {body}") # Return a response to acknowledge receipt of the event return jsonify({"received": True}) if __name__ == '__main__': PORT = 8000 print(f"Running on port {PORT}") app.run(port=PORT) ``` ```go Go package main import ( "crypto/hmac" "crypto/sha256" "encoding/base64" "encoding/hex" "encoding/json" "fmt" "net/http" "sort" "strings" ) const signingSecret = "c13cc017c4ed63bcc842c8edfb49df37512280326a32826de3b885340b8a3d53" // Canonicalize function sorts the JSON keys and produces a canonicalized string func Canonicalize(payload map[string]interface{}) (string, error) { var sb strings.Builder var keys []string for k := range payload { keys = append(keys, k) } sort.Strings(keys) sb.WriteString("{") for i, k := range keys { v, err := json.Marshal(payload[k]) if err != nil { return "", err } sb.WriteString(fmt.Sprintf("\"%s\":%s", k, v)) if i < len(keys)-1 { sb.WriteString(",") } } sb.WriteString("}") return sb.String(), nil } func isValidSignature(signingSecret, signature string, payload map[string]interface{}) bool { canonicalizedPayload, err := Canonicalize(payload) if err != nil { fmt.Println("Error canonicalizing payload:", err) return false } key, err := hex.DecodeString(signingSecret) if err != nil { fmt.Println("Error decoding signing secret:", err) return false } h := hmac.New(sha256.New, key) h.Write([]byte(canonicalizedPayload)) digest := h.Sum(nil) encodedDigest := base64.StdEncoding.EncodeToString(digest) fmt.Println("signature:", signature) fmt.Println("digest:", encodedDigest) return signature == encodedDigest } func callbackHandler(w http.ResponseWriter, r *http.Request) { var body map[string]interface{} err := json.NewDecoder(r.Body).Decode(&body) if err != nil { fmt.Println("Error decoding body:", err) http.Error(w, "Invalid request body", http.StatusBadRequest) return } signature := r.Header.Get("x-signature") eventType, ok := body["eventType"].(string) if !ok { fmt.Println("Error parsing eventType") http.Error(w, "Invalid event type", http.StatusBadRequest) return } switch eventType { case "address_activity": fmt.Println("*** Address_activity ***") fmt.Println(body) if isValidSignature(signingSecret, signature, body) { fmt.Println("match") } else { fmt.Println("no match") } default: fmt.Printf("Unhandled event type %s\n", eventType) } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]bool{"received": true}) } func main() { http.HandleFunc("/callback", callbackHandler) fmt.Println("Running on port 8000") http.ListenAndServe(":8000", nil) } ``` ```rust Rust use actix_web::{web, App, HttpServer, HttpResponse, Responder, post}; use serde::Deserialize; use hmac::{Hmac, Mac}; use sha2::Sha256; use base64::encode; use std::collections::BTreeMap; type HmacSha256 = Hmac; const SIGNING_SECRET: &str = "c13cc017c4ed63bcc842c8edfb49df37512280326a32826de3b885340b8a3d53"; #[derive(Deserialize)] struct EventPayload { eventType: String, // Add other fields as necessary } // Canonicalize the JSON payload by sorting keys fn canonicalize(payload: &BTreeMap) -> String { serde_json::to_string(payload).unwrap() } fn is_valid_signature(signing_secret: &str, signature: &str, payload: &BTreeMap) -> bool { let canonicalized_payload = canonicalize(payload); let mut mac = HmacSha256::new_from_slice(signing_secret.as_bytes()) .expect("HMAC can take key of any size"); mac.update(canonicalized_payload.as_bytes()); let result = mac.finalize(); let digest = encode(result.into_bytes()); println!("signature: {}", signature); println!("digest: {}", digest); digest == signature } #[post("/callback")] async fn callback(body: web::Json>, req: web::HttpRequest) -> impl Responder { let signature = req.headers().get("x-signature").unwrap().to_str().unwrap(); if let Some(event_type) = body.get("eventType").and_then(|v| v.as_str()) { match event_type { "address_activity" => { println!("*** Address_activity ***"); println!("{:?}", body); if is_valid_signature(SIGNING_SECRET, signature, &body) { println!("match"); } else { println!("no match"); } } _ => { println!("Unhandled event type: {}", event_type); } } } else { println!("Error parsing eventType"); return HttpResponse::BadRequest().finish(); } HttpResponse::Ok().json(serde_json::json!({ "received": true })) } #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() .service(callback) }) .bind("0.0.0.0:8000")? .run() .await } ``` ```TypeScript AvaCloud SDK import { isValidSignature } from '@avalabs/avacloud-sdk/utils'; import express from 'express'; const app = express(); app.use(express.json()); const signingSecret = 'your-signing-secret'; // Replace with your signing secret app.post('/webhook', (req, res) => { const signature = req.headers['x-signature']; const payload = req.body; if (isValidSignature(signingSecret, signature, payload)) { console.log('Valid signature'); // Process the request } else { console.log('Invalid signature'); } res.json({ received: true }); }); app.listen(8000, () => console.log('Server running on port 8000')); ``` # Supported EVM Chains Source: https://developers.avacloud.io/webhooks-api/supported-chains ### Supported L1s Webhooks are currently enabled for the following L1s. Additional L1s will be added in the future: **Mainnet** | L1 | Chain ID | | -------- | -------- | | Beam | 4337 | | DFK | 53935 | | Dexalot | 432204 | | Shrapnel | 2044 | | Testnet | Fuji | **Testnet** | L1 | Chain ID | | -------- | -------- | | Pulsar | 431234 | | Beam | 13337 | | Dexalot | 432201 | | DFK | 335 | | WAGMI | 11111 | | Shrapnel | 2038 | We will continue expanding this list by adding new L1s. # Add addresses to EVM activity webhook Source: https://developers.avacloud.io/webhooks-api/webhooks/add-addresses-to-webhook patch /v1/webhooks/{id}/addresses Add addresses to webhook. Only valid for EVM activity webhooks. # Create a webhook Source: https://developers.avacloud.io/webhooks-api/webhooks/create-a-webhook post /v1/webhooks Create a new webhook. # Deactivate a webhook Source: https://developers.avacloud.io/webhooks-api/webhooks/deactivate-a-webhook delete /v1/webhooks/{id} Deactivates a webhook by ID. # Generate or rotate a shared secret Source: https://developers.avacloud.io/webhooks-api/webhooks/generate-a-shared-secret post /v1/webhooks:generateOrRotateSharedSecret Generates a new shared secret or rotate an existing one. # Get a shared secret Source: https://developers.avacloud.io/webhooks-api/webhooks/get-a-shared-secret get /v1/webhooks:getSharedSecret Get a previously generated shared secret. # Get a webhook by ID Source: https://developers.avacloud.io/webhooks-api/webhooks/get-a-webhook-by-id get /v1/webhooks/{id} Retrieves a webhook by ID. # List adresses by EVM activity webhooks Source: https://developers.avacloud.io/webhooks-api/webhooks/list-adresses-by-webhook get /v1/webhooks/{id}/addresses List adresses by webhook. Only valid for EVM activity webhooks. # List webhooks Source: https://developers.avacloud.io/webhooks-api/webhooks/list-webhooks get /v1/webhooks Lists webhooks for the user. # Remove addresses from EVM activity webhook Source: https://developers.avacloud.io/webhooks-api/webhooks/remove-addresses-from-webhook delete /v1/webhooks/{id}/addresses Remove addresses from webhook. Only valid for EVM activity webhooks. # Update a webhook Source: https://developers.avacloud.io/webhooks-api/webhooks/update-a-webhook patch /v1/webhooks/{id} Updates an existing webhook. # WebSockets vs Webhooks Source: https://developers.avacloud.io/webhooks-api/wss-vs-webhooks Reacting to real-time events from Avalanche smart contracts allows for immediate responses and automation, improving user experience and streamlining application functionality. It ensures that applications stay synchronized with the blockchain state. There are two primary methods for receiving these on-chain events: * **WebSockets**, using libraries like Ethers.js or Viem * **Webhooks**, which send structured event data directly to your app via HTTP POST. Both approaches enable real-time interactions, but they differ drastically in their reliability, ease of implementation, and long-term maintainability. In this post, we break down why Webhooks are the better, more resilient choice for most Avalanche developers. ## Architecture Overview The diagram below compares the two models side-by-side: ![wss\_vs\_webhooks](https://mintlify.s3.us-west-1.amazonaws.com/avalabs-47ea3976/images/wss_vs_webhooks.png) **WebSockets** * The app connects to the Avalanche RPC API over WSS to receive raw log data. * It must decode logs, manage connection state, and store data locally. * On disconnection, it must re-sync via an external Data API or using standard `eth_*` RPC calls (e.g., `eth_getLogs`, `eth_getBlockByNumber`). Note: WSS is a transport protocol—not real-time by itself. Real-time capabilities come from the availability of `eth_subscribe`, which requires node support. **Webhooks** * The app exposes a simple HTTP endpoint. * Decoded event data is pushed directly via POST, including token metadata. * Built-in retries ensure reliable delivery, even during downtime. Important: Webhooks have a 48-hour retry window. If your app is down for longer, you still need a re-sync strategy using `eth_*` calls to recover older missed events. *** ## Using WebSockets: Real-time but high maintenance WebSockets allow you to subscribe to events using methods like eth\_subscribe. These subscriptions notify your app in real-time whenever new logs, blocks, or pending transactions meet your criteria. ```javascript import { createPublicClient, webSocket, formatUnits } from 'viem'; import { avalancheFuji } from 'viem/chains'; import { usdcAbi } from './usdc-abi.mjs'; // Ensure this includes the Transfer event // Your wallet address (case-insensitive comparison) const MY_WALLET = '0x8ae323046633A07FB162043f28Cea39FFc23B50A'.toLowerCase(); //Chrome async function monitorTransfers() { try { // USDC.e contract address on Avalanche Fuji const usdcAddress = '0x5425890298aed601595a70AB815c96711a31Bc65'; // Set up the WebSocket client for Avalanche Fuji const client = createPublicClient({ chain: avalancheFuji, transport: webSocket('wss://api.avax-test.network/ext/bc/C/ws'), }); // Watch for Transfer events on the USDC contract client.watchContractEvent({ address: usdcAddress, abi: usdcAbi, eventName: 'Transfer', onLogs: (logs) => { logs.forEach((log) => { const { from, to, value } = log.args; const fromLower = from.toLowerCase(); // Filter for transactions where 'from' matches your wallet if (fromLower === MY_WALLET) { console.log('*******'); console.log('Transfer from my wallet:'); console.log(`From: ${from}`); console.log(`To: ${to}`); console.log(`Value: ${formatUnits(value, 6)} USDC`); // USDC has 6 decimals console.log(`Transaction Hash: ${log.transactionHash}`); } }); }, onError: (error) => { console.error('Event watching error:', error.message); }, }); console.log('Monitoring USDC Transfer events on Fuji...'); } catch (error) { console.error('Error setting up transfer monitoring:', error.message); } } // Start monitoring monitorTransfers(); ``` The downside? If your connection drops, you lose everything in between. You’ll need to: * Set up a database to track the latest processed block and log index. * Correctly handling dropped connections and reconnection by hand can be challenging to get right. * Use `eth_getLogs` to re-fetch missed logs. * Decode and process raw logs yourself to rebuild app state. This requires extra infrastructure, custom recovery logic, and significant maintenance overhead. *** ## Webhooks: Resilient and developer-friendly Webhooks eliminate the complexity of managing live connections. Instead, you register an HTTP endpoint to receive blockchain event payloads when they occur. Webhook payload example: ```json { "eventType": "address_activity", "event": { "transaction": { "txHash": "0x1d8f...", "from": "0x3D3B...", "to": "0x9702...", "erc20Transfers": [ { "valueWithDecimals": "110.56", "erc20Token": { "symbol": "USDt", "decimals": 6 } } ] } } } ``` You get everything you need: * Decoded event data * Token metadata (name, symbol, decimals) * Full transaction context * No extra calls. No parsing. No manual re-sync logic. *** ## Key Advantages of Webhooks * **Reliable delivery with zero effort:** Built-in retries ensure no missed events during downtime * **Instant enrichment:** Payloads contain decoded logs, token metadata, and transaction context * **No extra infrastructure:** No WebSocket connections, no DB, no external APIs * **Faster development:** Go from idea to production with fewer moving parts * **Lower operational cost:** Less compute, fewer network calls, smaller surface area to manage If we compare using a table: | Feature | WebSockets (Ethers.js/Viem) | Webhooks | | | | :----------------------------- | :------------------------------------------------- | :--------------------------------------------------- | - | - | | **Interruption Handling** | Manual; Requires complex custom logic | Automatic; Built-in queues & retries | | | | **Data Recovery** | Requires DB + External API for re-sync | Handled by provider; No re-sync logic needed | | | | **Dev Complexity** | High; Error-prone custom resilience code | Low; Focus on processing incoming POST data | | | | **Infrastructure** | WSS connection + DB + Potential Data API cost | Application API endpoint | | | | **Data Integrity** | Risk of gaps if recovery logic fails | High; Ensures eventual delivery | | | | **Payload** | Often raw; Requires extra calls for context | Typically enriched and ready-to-use | | | | **Multiple addresses** | Manual filtering or separate listeners per address | Supports direct configuration for multiple addresses | | | | **Listen to wallet addresses** | Requires manual block/transaction filtering | Can monitor wallet addresses and smart contracts | | | ## Summary * WebSockets offer real-time access to Avalanche data, but come with complexity: raw logs, reconnect logic, re-sync handling, and decoding responsibilities. * Webhooks flip the model: the data comes to you, pre-processed and reliable. You focus on your product logic instead of infrastructure. * If you want to ship faster, operate more reliably, and reduce overhead, Webhooks are the better path forward for Avalanche event monitoring.