🕸ī¸General Inbox

Learn how to use Airstack to build General inbox and determine all the users that have a high probability connection with the given user. If they don't qualify, they should be in request inbox

The General inbox should contain all the users that a given user is likely to know or we have strong signals that they are a good actor.

Some criteria that can be checked for a user to be included in the general inbox are:

  • >X match score on Onchain Graph, which includes:

    • Sender has non-virtual POAPs in common with the user

    • Sender has minted >X NFTs in common with the user

    • Sender has several NFTs in common with the user

  • People the User follows are following the Sender on Farcaster

  • People the User follows are following the Sender on Lens

  • People the User follows have sent the Sender tokens

  • Senders have ENS and other factors (e.g. ENS + attended non-virtual POAPs)

If the sender doesn't meet the criteria, they should be removed from the main inbox and then placed into the Request Inbox.

Additionally, you can use XMTP Consent to check if a sender has given consent (has an Allowed consent value) to the sender before including them in the primary inbox. By default, you should place all senders that have been given consent directly into the Primary Inbox.

As demonstrated below, your app's interface can also feature user-friendly options for users to apply consent or deny consent. Applying consent should move the user to the Primary Inbox.

Table Of Contents

In this guide, you will learn how to use Airstack to build an XMTP general inbox by:

Pre-requisites

  • An Airstack account

  • Basic knowledge of GraphQL

  • Basic knowledge of XMTP

Get Started

JavaScript/TypeScript/Python

If you are using JavaScript/TypeScript or Python, Install the Airstack SDK:

React

npm install @airstack/airstack-react

Node

npm install @airstack/node

Then, add the following snippets to your code:

import { init, useQuery } from "@airstack/airstack-react";

init("YOUR_AIRSTACK_API_KEY");

const query = `YOUR_QUERY`; // Replace with GraphQL Query

const Component = () => {
  const { data, loading, error } = useQuery(query);

  if (data) {
    return <p>Data: {JSON.stringify(data)}</p>;
  }

  if (loading) {
    return <p>Loading...</p>;
  }

  if (error) {
    return <p>Error: {error.message}</p>;
  }
};

Other Programming Languages

To access the Airstack APIs in other languages, you can use https://api.airstack.xyz/gql as your GraphQL endpoint.

🤖 AI Natural Language​

Airstack provides an AI solution for you to build GraphQL queries to fulfill your use case easily. You can find the AI prompt of each query in the demo's caption or title for yourself to try.

Best Practice

While choosing a specific criteria will significantly decrease the number of spam appearing on your user's XMTP inbox, It is best practice that you combine the multiple criterion given here to build your General Inbox.

This is done to provide multiple layers of filtration that will make it nearly impossible for spammers to have their messages slide into your users' XMTP inbox.

Check If Senders' Onchain Graph Score Above X

To use this criteria, you will NEED TO have a dedicated backend to store user's onchain graph data from Airstack API.

To see if a user's onchain graph score is higher than a specific threshold (for example, value X), your application must already have an onchain graph feature. If it doesn't, follow this tutorial to add one:

🕸ī¸pageOnchain Graph

After implementing the onchain graph, you'll be able to examine the onchain connections between the user and the senders, assigning scores to each.

Besides the onchain graph score, you can also include other conditions to evaluate these criteria:

Common POAP Events Attended

You can use this query to filter senders on the fly with a maximum of 200 wallet inputs to the $senders variable per API call.

You can check if the senders have any common POAP events attended with the user by providing an array of senders' 0x addresses to the $senders variable and the user to the $mainUser variable using the Poaps API:

Try Demo

show me the common POAPs attended by the user and the senders

Code

query CommonPOAPs($mainUser: Identity!, $senders: [Identity!]) {
  Poaps(
    input: { filter: { owner: { _eq: $mainUser } }, blockchain: ALL, limit: 50 }
  ) {
    Poap {
      eventId
      poapEvent {
        poaps(input: { filter: { owner: { _in: $senders } } }) {
          owner {
            addresses
          }
        }
      }
    }
  }
}

Common NFT Collections Minted

You can check if the senders have any common NFT collections minted with the user by taking 2 steps.

First, fetch all the NFT addresses minted by the user by providing the user to the $mainUser variable using the TokenTransfers API:

For this check, you will need a backend to store all the NFT that the user minted

You can update the data on your end periodically to get the data most up to date.

Try Demo

Show me all NFTs minted by user

Code

query MyQuery($mainUser: Identity!) {
  Ethereum: TokenTransfers(
    input: {
      filter: {
        to: { _eq: $mainUser }
        operator: { _eq: $mainUser }
        from: { _eq: "0x0000000000000000000000000000000000000000" }
        tokenType: { _in: [ERC721, ERC1155] }
      }
      blockchain: ethereum
      limit: 50
    }
  ) {
    TokenTransfer {
      tokenAddress
    }
  }
  Polygon: TokenTransfers(
    input: {
      filter: {
        to: { _eq: $mainUser }
        operator: { _eq: $mainUser }
        from: { _eq: "0x0000000000000000000000000000000000000000" }
        tokenType: { _in: [ERC721, ERC1155] }
      }
      blockchain: polygon
      limit: 50
    }
  ) {
    TokenTransfer {
      tokenAddress
    }
  }
  Base: TokenTransfers(
    input: {
      filter: {
        to: { _eq: $mainUser }
        operator: { _eq: $mainUser }
        from: { _eq: "0x0000000000000000000000000000000000000000" }
        tokenType: { _in: [ERC721, ERC1155] }
      }
      blockchain: base
      limit: 50
    }
  ) {
    TokenTransfer {
      tokenAddress
    }
  }
  Zora: TokenTransfers(
    input: {
      filter: {
        to: { _eq: $mainUser }
        operator: { _eq: $mainUser }
        from: { _eq: "0x0000000000000000000000000000000000000000" }
        tokenType: { _in: [ERC721, ERC1155] }
      }
      blockchain: zora
      limit: 50
    }
  ) {
    TokenTransfer {
      tokenAddress
    }
  }
}

Once you have the list of NFT addresses from each chain, you can them compile them into an array and provide them as a variable input to the next query along with an array of senders' 0x addresses to the $senders variable to the TokenTransfers API:

You can use this query to filter senders on the fly with a maximum of 200 wallet inputs to the $senders variable per API call.

Try Demo

Show me all common NFTs minted by senders across Ethereum, Polygon, and Base

Code

query MyQuery(
  $senders: [Identity!],
  $ethereumNfts: [Address!],
  $polygonNfts: [Address!],
  $baseNfts: [Address!]
) {
  # Fetch Ethereum NFT mints
  Ethereum: TokenTransfers(
    input: {
      filter: {
        from: {_eq: "0x0000000000000000000000000000000000000000"},
        to: {_in: $senders},
        operator: {_in: $senders},
        tokenAddress: {_in: $ethereumNfts}
      },
      blockchain: ethereum
    }
  ) {
    TokenTransfer {
      to {
        addresses
      }
    }
  }
  # Fetch Polygon NFT mints
  Polygon: TokenTransfers(
    input: {
      filter: {
        from: {_eq: "0x0000000000000000000000000000000000000000"},
        to: {_in: $senders},
        operator: {_in: $senders},
        tokenAddress: {_in: $polygonNfts}
      },
      blockchain: polygon
    }
  ) {
    TokenTransfer {
      to {
        addresses
      }
    }
  }
  # Fetch Base NFT mints
  Base: TokenTransfers(
    input: {
      filter: {
        from: {_eq: "0x0000000000000000000000000000000000000000"},
        to: {_in: $senders},
        operator: {_in: $senders},
        tokenAddress: {_in: $baseNfts}
      },
      blockchain: base
    }
  ) {
    TokenTransfer {
      to {
        addresses
      }
    }
  }
  # No Zora as no Zora NFT is minted by user
}

Common NFT Collections Hold

You can check if the senders have any common NFT collections hold with the user by providing an array of senders' 0x addresses to the $senders variable and the user to the $mainUser variable using the TokenBalances API:

You can use this query to filter senders on the fly with a maximum of 200 wallet inputs to the $senders variable per API call.

Try Demo

Show me all common NFTs hold between user and sender

Code

query MyQuery($mainUser: Identity!, $senders: [Identity!]) {
  Ethereum: TokenBalances(
    input: {
      filter: {
        owner: { _eq: $mainUser }
        tokenType: { _in: [ERC1155, ERC721] }
      }
      blockchain: ethereum
      limit: 50
    }
  ) {
    TokenBalance {
      token {
        tokenBalances(input: { filter: { owner: { _in: $senders } } }) {
          tokenAddress
          owner {
            addresses
          }
        }
      }
    }
  }
  Polygon: TokenBalances(
    input: {
      filter: {
        owner: { _eq: $mainUser }
        tokenType: { _in: [ERC1155, ERC721] }
      }
      blockchain: polygon
      limit: 50
    }
  ) {
    TokenBalance {
      token {
        tokenBalances(input: { filter: { owner: { _in: $senders } } }) {
          tokenAddress
          owner {
            addresses
          }
        }
      }
    }
  }
  Base: TokenBalances(
    input: {
      filter: {
        owner: { _eq: $mainUser }
        tokenType: { _in: [ERC1155, ERC721] }
      }
      blockchain: base
      limit: 50
    }
  ) {
    TokenBalance {
      token {
        tokenBalances(input: { filter: { owner: { _in: $senders } } }) {
          tokenAddress
          owner {
            addresses
          }
        }
      }
    }
  }
  Zora: TokenBalances(
    input: {
      filter: {
        owner: { _eq: $mainUser }
        tokenType: { _in: [ERC1155, ERC721] }
      }
      blockchain: zora
      limit: 50
    }
  ) {
    TokenBalance {
      token {
        tokenBalances(input: { filter: { owner: { _in: $senders } } }) {
          tokenAddress
          owner {
            addresses
          }
        }
      }
    }
  }
}

Check If The Senders Followed By Those Followed by The User on Lens

For this check, you will need a backend to store the data fetched:

  • the user's followings on Lens

  • the addresses that is being followed by the user's followings on Lens

You can update the data on your end periodically to get the data most up to date.

You can check if the senders are is being followed by one of the Lens user followed by the given user on Lens by fetching data from Airstack twice.

First, fetch all the Lens followings of a user by providing the main user to the $mainUser variable using the SocialFollowers API:

Try Demo

Get all Lens followings of a given user

Code

query MyQuery($mainUser: Identity!) {
  # Get all the user's followers
  SocialFollowings(
    input: {
      filter: {
        identity: {_eq: $mainUser},
        # Only get followers on Lens
        dappName: {_eq: lens}
      },
      blockchain: ALL
    }
  ) {
    Following {
      followingAddress {
        addresses
      }
    }
  }
}

Then, compile the list of users followings and provide it as a variable input to $userFollowings by using the SocialFollowings API:

This query accepts a maximum of 200 wallet inputs to the $userFollowings variable per API call.

Try Demo

Show me all addresses that is being followed by the user's followings on Lens

Code

query MyQuery($userFollowers: [Identity!]) {
  # Get all the Lens followings of the user's followings
  SocialFollowings(
    input: {
      filter: {
        identity: {_in: $userFollowings},
        # Only check on Lens
        dappName: {_eq: lens}
      },
      blockchain: ALL
    }
  ) {
    Following {
      followingAddress {
        addresses
      }
    }
  }
}

Once you have all these data stored in your backend, you can use it to check whether the sender is one of the addresses that is being followed by the user's followings on Lens.

Check If The Senders Followed By Those Followed by The User on Farcaster

For this check, you will need a backend to store the data fetched:

  • the user's followings on Farcaster

  • the addresses that is being followed by the user's followings on Farcaster

You can update the data on your end periodically to get the data most up to date.

You can check if the senders are is being followed by one of the user's followings on Farcaster by fetching data from Airstack twice.

First, fetch all the Farcaster followings of a user by providing the main user to the $mainUser variable using the SocialFollowers API:

Try Demo

Code

query MyQuery($mainUser: Identity!) {
  # Get all the user's followings
  SocialFollowings(
    input: {
      filter: {
        identity: {_eq: $mainUser},
        # Only get followings on Farcaster
        dappName: {_eq: farcaster}
      },
      blockchain: ALL
    }
  ) {
    Following {
      followingAddress {
        addresses
      }
    }
  }
}

Then, compile the list of users followings and provide it as a variable input to $userFollowings by using the SocialFollowings API:

This query accepts a maximum of 200 wallet inputs to the $userFollowings variable per API call.

Try Demo

Code

query MyQuery($userFollowings: [Identity!]) {
  # Get all the Farcaster followings of the user's followings
  SocialFollowings(
    input: {
      filter: {
        identity: {_in: $userFollowings},
        # Only check on Farcaster
        dappName: {_eq: farcaster}
      },
      blockchain: ALL
    }
  ) {
    Following {
      followingAddress {
        addresses
      }
    }
  }
}

Once you have all these data stored in your backend, you can use it to check whether the sender is one of the addresses that is being followed by the user's followings on Farcaster.

Check If Any of The User's Followers on Lens or Farcaster Sent Any Token To The Sender

You can check if the senders are is being followed by one of the user's followers on Farcaster by fetching data from Airstack twice.

First, fetch all the Lens and Farcaster followers of a user by providing the main user to the $mainUser variable using the SocialFollowers API:

For this check, you will need a backend to store the user's followers on Lens and Farcaster.

You can update the data on your end periodically to get the data most up to date.

Try Demo

Code

query MyQuery($mainUser: Identity!) {
  # Get all the user's followers
  SocialFollowers(
    input: {
      filter: {
        identity: {_eq: $mainUser}
      },
      blockchain: ALL
    }
  ) {
    Follower {
      followerAddress {
        addresses
      }
    }
  }
}

Then, compile the list of users followers and provide it as a variable input to $userFollowers along with the senders' 0x address to the $senders variable by using the TokenTransfers API:

You can use this query to filter senders on the fly with a maximum of 200 wallet inputs to the $senders variable per API call.

Try Demo

Code

query MyQuery(
  $userFollowers: [Identity!],
  $senders: [Identity!]
) {
  # Check for any Ethereum Token Transfers
  Ethereum: TokenTransfers(
    input: {
      filter: {
        from: {_in: $userFollowers},
        to: {_in: $senders}
      },
      blockchain: ethereum
    }
  ) {
    TokenTransfer {
      to {
        addresses
      }
    }
  }
  # Check for any Polygon Token Transfers
  Polygon: TokenTransfers(
    input: {
      filter: {
        from: {_in: $userFollowers},
        to: {_in: $senders}
      },
      blockchain: polygon
    }
  ) {
    TokenTransfer {
      to {
        addresses
      }
    }
  }
  # Check for any Base Token Transfers
  Base: TokenTransfers(
    input: {
      filter: {
        from: {_in: $userFollowers},
        to: {_in: $senders}
      },
      blockchain: base
    }
  ) {
    TokenTransfer {
      to {
        addresses
      }
    }
  }
  # Check for any Zora Token Transfers
  Zora: TokenTransfers(
    input: {
      filter: {
        from: {_in: $userFollowers},
        to: {_in: $senders}
      },
      blockchain: zora
    }
  ) {
    TokenTransfer {
      to {
        addresses
      }
    }
  }
}

Check If XMTP Users Have Any ENS and Attended Any Non-Virtual POAPs

You can check if senders has any ENS and attended any non-virtual POAPs by providing the senders' 0x address to the $senders variable using the Poaps API:

You can use this query to filter senders on the fly with a maximum of 200 wallet inputs to the $senders variable per API call.

Try Demo

Code

query MyQuery($senders: [Identity!]) {
  Domains(
    input: { filter: { owner: { _in: $senders } }, blockchain: ethereum }
  ) {
    Domain {
      name
      owner
      ownerDetails {
        poaps {
          poapEvent {
            isVirtualEvent
            eventName
            eventId
          }
        }
      }
    }
  }
}

Developer Support

If you have any questions or need help regarding building your general inbox on your XMTP messaging app, please join our Airstack's Telegram group.

More Resources

Last updated

Was this helpful?