Notify API Quickstart

Setting up Alchemy Notify (webhooks) in your Ethereum, Polygon, Optimism, or Arbitrum dapp. Get notifications for external, internal, NFT, & token transfers, mined and dropped transactions.

Looking for the instructions on how to create webhooks programmatically? Check out the Notify API Endpoints!

Alchemy Notify works by using webhooks, a way for you to subscribe to events that occur on your application. This guide will walk through what webhooks are and how you can use them in order to get started with Alchemy Notify.


What are Webhooks?

Webhooks are a way for users to receive notifications when an event occurs on your application. Rather than continuously polling the server to check if the state has changed, webhooks provide information to you as it becomes available, which is a lot more efficient and beneficial for developers. Webhooks work by registering a URL to send notifications to once certain events occur.

Webhooks are typically used to connect two different applications. One application is the "sender," which subscribes to events and sends them off to the the second "receiver" application, which takes actions based upon that received data. When an event occurs on the sender application it sends that data to the webhook URL of the receiver application. The receiver application can then send a callback message, with an HTTP status code to let the sender know the data was received successfully or not.

You can think of webhook notifications just like SMS notifications. The entity sending the message has your registered phone number and they send a specific message payload to that phone number. You then have the ability to respond confirming you have received it, creating a two-way communication stream.

📘

Webhooks vs. WebSockets:

The difference between webhooks and WebSockets is that webhooks can only facilitate one-way communication between two services, while WebSockets can facilitate two-way communication between a user and a service, recognizing events and displaying them to the user as they occur.


Types of Webhooks

There are four types of webhooks to receive notifications for:

  1. Mined Transactions (all networks)
  2. Dropped Transactions (all networks)
  3. Address Activity (all networks)
  4. NFT Activity (Ethereum: Mainnet, Goerli, Rinkeby)

Webhook Format

The following format applies to all webhooks.

V2

  • webhookId: Unique id for the webhook that this event was sent to
  • id: Unique id of the event itself
  • createdAt: Timestamp that the webhook event was created (might be different from the block timestamp that the event was in)
  • type: Type of webhook event, can be "MINED_TRANSACTION", "DROPPED_TRANSACTION", "NFT_ACTIVITY", or "ADDRESS_ACTIVITY"
  • event: Object - event object, see mined transaction object, dropped transaction object, address activity, and NFT activity object below.

Example Response

{
 "webhookId": "wh_octjglnywaupz6th",
 "id": "whevt_ogrc5v64myey69ux",
 "createdAt": "2021-12-07T03:52:45.899Z",
 "type": TYPE_STRING,
 "event": OBJECT
}

V1

  • app: Alchemy app name that sent the transaction and is configured to this webhook
  • network: Network for the event, can be Ethereum only
    MAINNET, GOERLI, ROPSTEN, RINKEBY, KOVAN
  • webhookType: Type of webhook event, can be "MINED_TRANSACTION", "DROPPED_TRANSACTION", "ADDRESS_ACTIVITY"
  • timestamp: Timestamp that the webhook event was created (might be different from the block timestamp that the event was in)
  • event: Object - event object, see mined transaction object, dropped transaction object, address activity, and NFT activity object below.

Example Response

{
  "app": "Demo", 
  "network": "MAINNET",
  "webhookType": "MINED_TRANSACTION",
  "timestamp": "2020-07-29T00:29:18.414Z",
  "event name": OBJECT
}

1. Mined Transaction

The Mined Transaction Webhook is used to notify your app anytime a transaction sent through your API key gets successfully mined. This is extremely useful if you want to notify customers the moment their transactions goes through.

Example Response

V2

Event Object:

event: Object-mined transaction object

  • appId: Unique ID for Alchemy app that sent the transaction and is configured to this webhook
  • network: Network for the event, can be
    ARB_MAINNET, ARB_RINKEBY, MATIC_MAINNET, MATIC_MUMBAI, OPT_MAINNET, OPT_KOVAN,
    ETH_MAINNET, ETH_GOERLI, ETH_ROPSTEN, ETH_RINKEBY, ETH_KOVAN
  • transaction: transaction object (same output as calling eth_getTransactionByHash)

V1

Event Object:

Object - mined transaction object

Example

{
 "webhookId": "wh_octjglnywaupz6th",
 "id": "whevt_ogrc5v64myey69ux",
 "createdAt": "2021-12-07T03:52:45.899Z",
 "type": "MINED_TRANSACTION",
 "event": {
  "appId": "j6tqmhfxlu9pa5r7",
  "network": "MATIC_MUMBAI",
  "transaction": {
   "blockHash": "0x0a50cb2068418da0d7746155be39cff624aaf6fca58fa7f86f139999947433db",
   "blockNumber": "0x154f434",
   "from": "0x829e20741ee472f628b260a591f9f78fb1a555f8",
   "gas": "0x5208",
   "gasPrice": "0xdf8475800",
   "hash": "0xc981aed4304084ddf2b82859c80dd31334fad3bcf2aa7ee15dfd646af0889b7d",
   "input": "0x",
   "nonce": "0x8",
   "to": "0x4577d79fc84838aee64ba8be8d250981dd4f3876",
   "transactionIndex": "0x1",
   "value": "0x0",
   "type": "0x0",
   "v": "0x27125",
   "r": "0xc07a6670796726674e213c4cf61763b59490b1b1c992b9323a1aad5e3c2cea88",
   "s": "0x22ce350c260b3dbd1ebc06ca00b18c127efd6c1b31136a104de1a6ea4aa3c0d2"
  }
 } 
}
{
  "app": "Demo", 
  "network": "MAINNET",
  "webhookType": "MINED_TRANSACTION",
  "timestamp": "2020-07-29T00:29:18.414Z",
  "fullTransaction": {
    "hash": "0x5a4bf6970980a9381e6d6c78d96ab278035bbff58c383ffe96a0a2bbc7c02a4b",
    "blockHash": "0xaa20f7bde5be60603f11a45fc4923aab7552be775403fc00c2e6b805e6297dbe",
    "blockNumber": "0x989680",
    "from": "0x8a9d69aa686fa0f9bbdec21294f67d4d9cfb4a3e",
    "gas": "0x5208",
    "gasPrice": "0x165a0bc00",
    "input": "0x",
    "nonce": "0x2f",
    "r": "0x575d26288c1e3aa63e80eea927f54d5ad587ad795ad830149837258344a87d7c",
    "s": "0x25f5a3abf22f5b8ef6ed307a76e670f0c9fb4a71fab2621fce8b52da2ab8fe82",
    "to": "0xd69b8ff1888e78d9c337c2f2e6b3bf3e7357800e",
    "transactionIndex": "0x66",
    "v": "0x1c",
    "value": "0x1bc16d674ec80000"
  }
}

2. Dropped Transactions

The Dropped Transactions Webhook is used to notify your app anytime a transaction send through your API key gets dropped.

Example Response

V2

Event Object:
event: Object - dropped transaction object

  • appId: Unique ID for Alchemy app that sent the transaction and is configured to this webhook
  • network: Network for the event, can be ARB_MAINNET, ARB_RINKEBY, MATIC_MAINNET, MATIC_MUMBAI, OPT_MAINNET, OPT_KOVAN,ETH_MAINNET, ETH_GOERLI, ETH_ROPSTEN, ETH_RINKEBY, ETH_KOVAN
  • transaction: transaction object (same output as calling eth_getTransactionByHash)

V1

Event Object:
Object - dropped transaction object

Example

{
 "webhookId": "wh_octjglnywaupz6th",
 "id": "whevt_ogrc5v64myey69ux",
 "createdAt": "2021-12-07T03:52:45.899Z",
 "type": "DROPPED_TRANSACTION",
 "event": {
  "appId": "j6tqmhfxlu9pa5r7",
  "network": "OPT_MAINNET",
  "transaction": {
   "hash": "0x5a4bf6970980a9381e6d6c78d96ab278035bbff58c383ffe96a0a2bbc7c02a4b",
    "blockHash": null,
    "blockNumber": null,
    "from": "0x8a9d69aa686fa0f9bbdec21294f67d4d9cfb4a3e",
    "gas": "0x5208",
    "gasPrice": "0x165a0bc00",
    "input": "0x",
    "nonce": "0x2f",
    "r": "0x575d26288c1e3aa63e80eea927f54d5ad587ad795ad830149837258344a87d7c",
    "s": "0x25f5a3abf22f5b8ef6ed307a76e670f0c9fb4a71fab2621fce8b52da2ab8fe82",
    "to": "0xd69b8ff1888e78d9c337c2f2e6b3bf3e7357800e",
    "transactionIndex": null,
    "v": "0x1c",
    "value": "0x1bc16d674ec80000"
  }
 } 
}
{
  "app": "Alchemy Mainnet",
  "network": "MAINNET",
  "webhookType": "DROPPED_TRANSACTION",
  "timestamp": "2020-06-08T22:12:57.126Z",
  "fullTransaction": {
    "hash": "0x5a4bf6970980a9381e6d6c78d96ab278035bbff58c383ffe96a0a2bbc7c02a4b",
    "blockHash": null,
    "blockNumber": null,
    "from": "0x8a9d69aa686fa0f9bbdec21294f67d4d9cfb4a3e",
    "gas": "0x5208",
    "gasPrice": "0x165a0bc00",
    "input": "0x",
    "nonce": "0x2f",
    "r": "0x575d26288c1e3aa63e80eea927f54d5ad587ad795ad830149837258344a87d7c",
    "s": "0x25f5a3abf22f5b8ef6ed307a76e670f0c9fb4a71fab2621fce8b52da2ab8fe82",
    "to": "0xd69b8ff1888e78d9c337c2f2e6b3bf3e7357800e",
    "transactionIndex": null,
    "v": "0x1c",
    "value": "0x1bc16d674ec80000"
  }
}

3. Address Activity

The Address Activity Webhook allows you to track all ETH, ERC20 and ERC721 Deep Dive into eth_getLogs for as many Ethereum addresses as you'd like. This provides your app with real-time state changes when an address sends or receives tokens.

📘

NOTE:

If you are looking for historical activity, check out the Transfers API Endpoints.

Types of Transfers

There are three main types of transfers that are captured when receiving an address activity response.

1. External Eth Transfers

These are top-level transactions that occur with a from address being an external (user created) address. External addresses have private keys and are accessed by users.

2. Token Transfers (ERC20, ERC721, ERC1155)

These are event logs for any ERC20, ERC721, and ERC1155 transfers.

3. Internal Eth Transfers

These are transfers that occur where the fromAddress is an internal (smart contract) address. (ex: a smart contract calling another smart contract or smart contract calling another external address).

❗️

Note on Internal Transfers

  • Internal transfers are only available on the following networks:
    • ETH_MAINNET
    • ETH_GOERLI
    • ETH_RINKEBY
  • We do not include any internal transfers with call type delegatecall because although they have a "value" associated with them they do not actually transfer that value (see Appendix H of the Ethereum Yellow Paper if you're curious). We also do not include miner rewards as an internal transfer.

Example Response

V2

Event Object:

event: Object - address activity object

  • network: Network for the event, can be ARB_MAINNET, ARB_RINKEBY, MATIC_MAINNET, MATIC_MUMBAI, OPT_MAINNET, OPT_KOVAN,ETH_MAINNET, ETH_GOERLI, ETH_ROPSTEN, ETH_RINKEBY, ETH_KOVAN
  • activity: List of transfer events whose from or to address matches the address configured in the webhook. Events are included in the same list if they occurred in the same block, each transfer event has the following values.
    • fromAddress: from the address of transfer (hex string).
    • toAddress: to address of transfer (hex string). Omitted if contract creation.
    • blockNum: the block where the transfer occurred (hex string).
    • hash: transaction hash (hex string).
    • category: external, internal, or token- label for the transfer
    • value: converted asset transfer value as a number (raw value divided by contract decimal). Omitted if erc721 transfer or contract decimal is not available.
    • asset: ETH or the token's symbol. Omitted if not defined in the contract and not available from other sources.
    • erc721TokenId: raw erc721 token id (hex string). Omitted if not an erc721 token transfer
    • erc1155Metadata: A list of objects containing the ERC1155 tokenId (hex string) and value (hex string). Omitted if not an ERC1155 transfer
    • rawContract
      • rawValue: raw transfer value (hex string). Omitted if erc721 transfer
      • address: contract address (hex string). Omitted if external or internal transfer
      • decimal: contract decimal (hex string). Omitted if not defined in the contract and not available from other sources.
    • typeTraceAddress: the type of internal transfer (call, staticcall, create, suicide) followed by the trace address (ex. call_0_1).Omitted if not internal transfer. (note you can use this as a unique id for internal transfers since they will have the same parent hash)
    • log : log emitted for the token transfer event. Omitted if external or internal transfer

V1

Event Object:

Object - address activity object

  • activity: List of transfer events whose from or to address matches the address configured in the webhook. Events are included in the same list if they occurred in the same block, each transfer event has the following values.
    • category: external, internal, or token- label for the transfer
    • blockNum: the block where the transfer occurred (hex string).
    • fromAddress: from the address of transfer (hex string).
    • toAddress: to address of transfer (hex string). null if contract creation.
    • value: converted asset transfer value as a number (raw value divided by contract decimal). null if erc721 transfer or contract decimal not available.
    • erc721TokenId: raw erc721 token id (hex string). null if not an erc721 token transfer
    • asset: ETH or the token's symbol. null if not defined in the contract and not available from other sources.
    • hash: transaction hash (hex string).
    • rawContract
      • rawValue: raw transfer value (hex string). null if erc721 transfer
      • address: contract address (hex string). null if external or internal transfer
      • decimal: contract decimal (hex string). null if not defined in the contract and not available from other sources.
    • typeTraceAddress: the type of internal transfer (call, staticcall, create, suicide) followed by the trace address (ex. call_0_1).null if not internal transfer. (note you can use this as a unique id for internal transfers since they will have the same parent hash)
    • log: log emitted for this transfer event

Example

{
  "webhookId": "wh_octjglnywaupz6th",
  "id": "whevt_ogrc5v64myey69ux",
  "createdAt": "2022-02-28T17:48:53.306Z",
  "type": "ADDRESS_ACTIVITY",
  "event": {
    "network": "MATIC_MAINNET",
    "activity": [
      {
        "category": "token",
        "fromAddress": "0x59479de9d374bdbcba6c791e5d036591976fe422",
        "toAddress": "0x59479de9d374bdbcba6c791e5d036591976fe425",
        "erc721TokenId": "0x1",
        "rawContract": {
          "rawValue": "0x",
          "address": "0x93C46aA4DdfD0413d95D0eF3c478982997cE9861"
        },
        "log": {
          "removed": false,
          "address": "0x93C46aA4DdfD0413d95D0eF3c478982997cE9861",
          "data": "0x",
          "topics": [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
            "0x00000000000000000000000059479de9d374bdbcba6c791e5d036591976fe422",
            "0x00000000000000000000000059479de9d374bdbcba6c791e5d036591976fe425",
            "0x0000000000000000000000000000000000000000000000000000000000000001"
          ]
        }
      }
    ]
  }
}

4. NFT Activity

The NFT Activity Webhook allows you to track all ERC721 and ERC1155 for as many Ethereum NFTs as you'd like. This provides your app with real-time state changes when an NFT is transferred between addresses.

Example Response

V2

Event Object:

event: Object - address activity object

  • network: Network for the event, can be ETH_MAINNET, ETH_GOERLI, ETH_RINKEBY`
  • activity: List of transfer events whose involving the NFTs configured in the webhook. Events are included in the same list if they occurred in the same block, each transfer event has the following values.
    • fromAddress: from address of the NFT transfer (hex string).
    • toAddress: to address of the NFT transfer (hex string).
    • blockNumber: the block where the transfer occurred (hex string).
    • blockHash: block hash (hex string).
    • transactionHash: transaction hash (hex string).
    • category: erc721, or erc1155
    • asset: ETH or the token's symbol. Omitted if not defined in the contract and not available from other sources.
    • tokenId: raw NFT token id (hex string).
    • erc1155Metadata: A list of objects containing the ERC1155 tokenId (hex string) and value (hex string). Omitted if not an ERC1155 transfer
    • log : log emitted for the token transfer event.

Example

{
  "webhookId": "wh_v394g727u681i5rj",
  "id": "whevt_13vxrot10y8omrdp",
  "createdAt": "2022-08-03T23:29:11.267808614Z",
  "type": "NFT_ACTIVITY",
  "event": {
    "fromAddress": "0x15dd13f3c4c5279222b5f09ed1b9e9340ed17185",
    "toAddress": "0xfae46f94ee7b2acb497cecaff6cff17f621c693d",
    "erc1155Metadata": [
      {
        "tokenId": "0x15dd13f3c4c5279222b5f09ed1b9e9340ed17185000000000000020000000001",
        "value": "0x1"
      }
    ],
    "category": "erc1155",
    "log": {
      "address": "0x88b48f654c30e99bc2e4a1559b4dcf1ad93fa656",
      "topics": [
        "0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62",
        "0x00000000000000000000000015dd13f3c4c5279222b5f09ed1b9e9340ed17185",
        "0x00000000000000000000000015dd13f3c4c5279222b5f09ed1b9e9340ed17185",
        "0x000000000000000000000000fae46f94ee7b2acb497cecaff6cff17f621c693d"
      ],
      "data": "0x15dd13f3c4c5279222b5f09ed1b9e9340ed171850000000000000200000000010000000000000000000000000000000000000000000000000000000000000001",
      "blockNumber": "0xa98a55",
      "transactionHash": "0xc8d14d6649a186e6609fce2ac7c46145347ee9e2f0ba32869452755db5c668a1",
      "transactionIndex": "0x6",
      "blockHash": "0x44bd2324fc1343e862e34a94a1d5d573c80713ff62f1f7fcb0187837b13eb66b",
      "logIndex": "0xd",
      "removed": false
    }
  }
}

Test Out Webhooks

There are many tools you can use to test out webhooks. In this guide, you will learn how to use ngrok, which allows you to test your webhooks locally.

To set up ngrok:

  1. Sign up for a free ngrok account
  2. Install ngrok using the ngrok guide or if you are on macOS run: brew install ngrok
  3. Connect your ngrok account by running: ngrok authtoken YOUR_AUTH_TOKEN
  4. Fire up your local forwarding tunnel: ngrok http 80
13001300

Once you have a URL to test your webhook (in this case https://461a-199-116-73-171.ngrok.io from the picture above), you can test using the following steps:

  1. Navigate to your Notify dashboard
  2. Click "Create Webhook" on the webhook you want to test
  3. Paste in your unique URL and hit the "Test Webhook" button

If you are using ngrok, you should then see the webhooks roll in here: http://localhost:4040/inspect/http


How to Set Up Webhooks

Setting up a webhook is as simple as adding a new URL to your application. There are two primary ways to activate Alchemy Notify.

❗️

NOTE:

If you need to add over 10 addresses to the address activity webhook, we recommend adding them through an API call. See our Notify API Reference page for more information on this.

1. Setting Up Webhooks from the Dashboard

Navigate to the Notify tab in your Alchemy Dashboard

  1. Determine which type of webhook you want to activate
  2. Click the "Create Webhook" button
  3. Specify which app you wish to add notifications to
  4. Add in your unique webhook URL, this can be any link that you want to receive requests at (your server, slack, etc.) Note that the webhook payload might not always be compatible for 3rd party integrations.
  5. Test out your webhook by hitting the "Test Webhook" button to ensure it works properly
  6. Hit "Create Webhook" and you should then see your webhook appear in the list!
  7. Check your endpoint to see responses rolling through!

2. Setting up Webhooks Programmatically

See Notify API Page below:


Webhook Signature and Security

If you want to make your webhooks extra secure, you can verify that they originated from Alchemy by generating a HMAC SHA-256 hash code using your unique webhook signing key.

1. Find your signing key

Navigate to the Notify page in your dashboard, click on the three dots for the webhook you want to get the signature for and copy the "signing key".

24142414

2. Validate the signature received

Every outbound request will contain a hashed authentication signature in the header which is computed by concatenating your signing key and request body then generating a hash using the HMAC SHA256 hash algorithm.

In order to verify this signature came from Alchemy, you simply have to generate the HMAC SHA256 hash and compare it with the signature received.

Example Request Header

POST /yourWebhookServer/push HTTP/1.1
Content-Type: application/json;
X-Alchemy-Signature: your-hashed-signature

Example Signature Validation Function

  • body: must be raw string body, not json transformed version of the body
  • signature: your "X-Alchemy-Signature" received from header
  • signing_key: Signing key from dashboard, see above on how to find it
import * as crypto from "crypto";

function isValidSignatureForStringBody(
    body: string, // must be raw string body, not json transformed version of the body
    signature: string, // your "X-Alchemy-Signature" from header
    signingKey: string, // taken from dashboard for specific webhook
  ): boolean {
    const hmac = crypto.createHmac("sha256", signingKey); // Create a HMAC SHA256 hash using the signing key
    hmac.update(body, "utf8"); // Update the token hash with the request body using utf8
    const digest = hmac.digest("hex");
    return signature === digest;
}
import * as crypto from "crypto";

function isValidSignatureForStringBody(
    body: string, // must be raw string body, not json transformed version of the body
    signature: string, // your "X-Alchemy-Signature" from header
    signingKey: string, // taken from dashboard for specific webhook
  ): boolean {
    const hmac = crypto.createHmac("sha256", signingKey); // Create a HMAC SHA256 hash using the signing key
    hmac.update(body, "utf8"); // Update the token hash with the request body using utf8
    const digest = hmac.digest("hex");
    return signature === digest;
}
func isValidSignatureForStringBody(
  body []byte, // must be raw string body, not json transformed version of the body
  signature string, // your "X-Alchemy-Signature" from header
  signingKey []byte, // taken from dashboard for specific webhook
) bool {
  h := hmac.New(sha256.New, signingKey)
  h.Write([]byte(body))
  digest := hex.EncodeToString(h.Sum(nil))
  return digest == signature
}
fn is_valid_signature_for_string_body(
    body: &[u8], // must be raw string body, not json transformed version of the body
    signature: &str, // your "X-Alchemy-Signature" from header
    signing_key: &str, // taken from dashboard for specific webhook
) -> Result<bool, Box<dyn std::error::Error>> {
    let signing_key_bytes: Vec<u8> = signing_key.bytes().collect();
    let mut mac = Hmac::<Sha256>::new_from_slice(&signing_key_bytes)?;
    mac.update(&body);
    let hex_decode_signature = hex::decode(signature)?;
    let verification = mac.verify_slice(&hex_decode_signature).is_ok();
    Ok(verification)
}

Webhook Retry-logic

Alchemy Notify V2 has built-in retry-logic for webhooks. Here is some information you need to know on how retry-logic works.

When are requests retried?

Requests are retried for non-200 response codes and upon failures to reach your server

How often are requests retried?

Requests are retried up to 6 times before failing over. Here are the times after the initial failure that the request is retried, with each time interval building off the previous:

  1. 15 seconds
  2. 1 minute
  3. 10 minutes
  4. 1 hour
  5. 1 day
  6. 1 day

Common Questions

Capacity Limit

If you receive a capacity limit error, meaning you have exceeded your total monthly compute units, you should receive a response similar to the one below. You can upgrade your limits directly through the Alchemy dashboard.

{
  "app": "Demo",
  "network": "MAINNET",
  "error": "Monthly capacity limit exceeded. Upgrade your scaling policy for continued service.",
  "webhookType": "MINED_TRANSACTION",
  "timestamp": "2020-07-29T01:13:54.703Z"
}

Webhook IP Addresses

As an added security measure, you can ensure your webhook notification originated from Alchemy by verifying that the event originated from one of the following IP addresses:

❗️

NOTE:

This does not apply for test webhooks done through the Notify dashboard.

54.236.136.17
34.237.24.169

How many addresses can you add to a single webhook?

We recommend no more than 50,000 addresses per single webhook. There is no current limit on how many webhooks you can create.

What's the difference between Notify V1 and V2?

The changes in webhook V2 are mostly formatting and parameter name differences. Thus, the primary changes that will need to be made are how you process response payloads.

To learn more about why we made this change, check out the blog post here. Although V1 webhooks will still be supported, all net-new webhooks created after Wednesday, April 27, 2022 will be V2.

Here is an overview of the changes from V1 to V2:

[notify

  • app is replaced with appId field and is now under the event field.
  • network field is now under the event field.
  • app field is no longer included for Address Activity webhooks.
  • webhookType is renamed to type.
  • webhook_id changed from an int to a string.
  • timestamp is renamed to createdAt
  • fullTransaction is renamed to transaction, which is under the event field
  • null fields will be omitted from the response payload entirely to improve latency and save users on bandwidth

Why am I missing transactions in the response?

Double check that you are parsing the response payload correctly- remember, transactions are returned in a list! Transactions that are mined within the same block will be returned within the same "activity" list.

What are some best practices when using webhooks with a large number of addresses?

When working with large address lists, we suggest that users assign no more than 50,000 addresses to each webhook. If you find yourself using many addresses, spin up a new webhook to ensure that you have a reliable and scalable system.