Transfer existing NFT tokens via Alchemy Web3

I created some NFT tokens on OpenSea using the Polygon Mumbai testnet. Now I need to move these tokens to different wallet addresses through Alchemy Web3 integration.

I’m building this for a Node.js REST API backend, so I don’t have access to browser wallets. That’s why I need to sign transactions manually with private keys.

Here’s my current implementation:

async function transferNFT() {
  require('dotenv').config();
  const { RPC_URL, WALLET_PRIVATE_KEY } = process.env;
  const { createAlchemyWeb3 } = require("@alch/alchemy-web3");
  const web3Instance = createAlchemyWeb3(RPC_URL);
  
  const senderAddress = '*************************';
  const currentNonce = await web3Instance.eth.getTransactionCount(senderAddress, 'latest');
  
  // I think this transaction structure is wrong but not sure what fields to use
  const txData = {
    'asset': {
      'tokenId': '******************************', // NFT ID from OpenSea
    },
    'gas': 53000,
    'to': '***********************', // recipient wallet address
    'quantity': 1,
    'nonce': currentNonce,
  };
 
  const signedTransaction = await web3Instance.eth.accounts.signTransaction(txData, WALLET_PRIVATE_KEY);
  
  web3Instance.eth.sendSignedTransaction(signedTransaction.rawTransaction, function(err, txHash) {
    if (!err) {
      console.log("✅ Transaction hash: ", txHash);
    } else {
      console.log("❌ Transaction failed:", err);
    }
  });
}

transferNFT();

What’s the correct transaction format for transferring NFTs?

u cant send NFTs like regular ETH transactions! NFTs r smart contracts, so u gotta call the contract’s transfer function. use the contract ABI and call safeTransferFrom with from/to addresses plus tokenId. also, your gas limit’s way too low for Polygon - try 200k+.

Your transaction structure is completely wrong - you’re treating the NFT transfer like a regular ETH transaction. NFTs are smart contracts, so you need to call specific functions using the contract’s ABI and call the transfer method directly. I ran into this exact same issue when I first started working with NFTs on backend services. You need the contract address of your NFT collection and its ABI. Then use web3’s contract interface to call safeTransferFrom(from, to, tokenId) for ERC-721 tokens. Here’s what you should do: instantiate the contract with new web3.eth.Contract(ABI, contractAddress), then call the transfer method and sign that transaction data. Your transaction object needs the standard fields - from, to (contract address), data (encoded function call), gas, and nonce. Also, your gas limit is way too low. Even on Mumbai testnet, NFT transfers usually need around 200k gas minimum. Contract interactions are much more complex than simple ETH transfers.

hey @Mia_17Dance, interesting challenge! few questions about your setup - are you working with ERC-721 or ERC-1155 tokens? makes a difference in how you structure the transfer call.

the previous answer’s right about needing the contract ABI, but have you actually grabbed the contract address for your NFT collection yet? you’ll need that first. also, did you check what standard your opensea collection uses?

one thing caught my attention - you mentioned these are tokens you created on opensea using polygon mumbai. are these actually minted through opensea’s lazy minting, or did you deploy your own contract? if they’re lazy minted, they might not exist on-chain until the first transfer.

have you tried looking up your NFT on polygonscan to see the contract details? that’ll give you the contract address and you can grab the ABI from there. also curious what error message you’re getting when you run this code - might give us more clues.

btw, for polygon mumbai gas prices are usually pretty low, but 53000 is definitely too low for an NFT transfer. usually need at least 150k-250k depending on contract complexity.