Back

Blog details

How to Store NFT Metadata on IPFS and Mint with AIOZ Pin

AIOZ Network
6 min readAugust 13, 2026
aioz-pinnfttutorial
AIOZ Pin cover image with the headline How to Store NFT Metadata on IPFS, Then Mint

To store NFT metadata on IPFS so it lasts, pin it before minting. Pin the asset and its metadata JSON together, check that both CIDs load, then put ipfs://<metadata CID> on chain as the token URI. The contract stores only that pointer, so the pin keeps your NFT intact.

TL;DR:

  • Write the metadata JSON first. Any change after pinning gives a new CID.
  • Pin asset and metadata in one request, with POST /api/nft/ or the SDK's pinNft. You get back an asset_cid and a metadata_cid.
  • Before minting, confirm the NFT record shows pinned and that the metadata loads through a gateway.
  • ERC-721 returns the URI from tokenURI(tokenId). ERC-1155 uses uri(id), which may contain an {id} placeholder.

Updated Oct 19, 2026: fixed the ERC-1155 function (it's uri(id), not tokenURI). The SDK and verification code now follow the docs, and there's a workflow diagram and contract examples.

Why does NFT metadata need to be pinned before minting?

A mint writes one string to the chain: the token URI. Everything a wallet or marketplace shows, the name, the image, the traits, comes from the JSON at that URI. If the URI points at an IPFS CID that nobody hosts, the token still exists, but it shows a blank card.

So the order matters. Pin first, and your contract never references a CID that doesn't exist yet. Verify the pin, and you catch failures while they're still cheap. A broken pin before minting means a retry. A broken pin after minting means a token you may not be able to fix. The NFT metadata problem shows what happens when a pin lapses.

Workflow diagram: prepare the asset and metadata, pin them together with POST /api/nft/, verify the pin, then mint with ipfs://metadata_cid returned by tokenURI in ERC-721 or uri in ERC-1155

Step 1: Prepare the asset and metadata

Start with the file the NFT represents: an image, video, or audio track. Then write the metadata object. The AIOZ Pin NFT docs and SDK README use this shape: a name, a description, and a properties array of trait_type/value pairs.

const metadata = {
  name: 'Artwork #001',
  description: 'A generative piece from the Genesis collection',
  properties: [
    { trait_type: 'Background', value: 'Deep Blue' },
    { trait_type: 'Rarity', value: 'Rare' }
  ]
}

Get it right now. A CID comes from the content, so editing one field later gives you a new CID, not an updated old one. Marketplaces also differ in which trait field they read, so check your target marketplace's metadata docs before you pin a whole collection.

Step 2: Pin the asset and metadata together

The SDK's pinNft pins both in one call. Behind it is the documented POST /api/nft/ endpoint, which takes the asset and the metadata JSON in one multipart request. Pinning them as one record avoids the case where the metadata survives but the asset it describes doesn't.

// npm install @aioznetwork/aioz-pin-sdk   (package.json needs "type": "module")
import fs from 'fs'
import AiozPinClient from '@aioznetwork/aioz-pin-sdk'

const client = new AiozPinClient(process.env.AIOZ_PIN_API_KEY, process.env.AIOZ_PIN_SECRET_KEY)

const result = await client.pinNft({
  fileStream: fs.createReadStream('./artwork.png'),
  metadata
})

const { id, asset_cid, metadata_cid } = result.data
console.log(id, asset_cid, metadata_cid)

This follows the SDK README for version 1.0.1. We didn't run it, since there are no AIOZ Pin credentials on this machine. One naming note: the README's install line still shows an older unscoped package name, while the AIOZ Pin docs give @aioznetwork/aioz-pin-sdk, the name published on npm.

The AIOZ Pin ERC-1155 tutorial says the service updates the metadata to link to the asset with an IPFS URI. The docs don't show which field that link goes in, so look at the stored JSON in Step 3 before you mint.

Step 3: Verify the pin before you mint

Don't assume a successful call means a finished pin. Read the NFT record back with GET /api/nft/{nftId}, as the AIOZ Pin docs show, and check that pinned is true:

const res = await fetch(`https://api.aiozpin.network/api/nft/${id}`, {
  headers: {
    'pinning_api_key': process.env.AIOZ_PIN_API_KEY,
    'pinning_secret_key': process.env.AIOZ_PIN_SECRET_KEY
  }
})
const nft = await res.json()
console.log(nft.data.pinned, nft.data.status, nft.data.metadata_cid)

Then fetch the metadata the way a buyer's wallet will, over a gateway. Use the gateway URL format from the AIOZ Pin docs, and check one gateway you don't control as well (commands not run here):

# Does the metadata load, and does it point at the asset?
curl -s https://public.aiozpin.network/ipfs/<metadata_cid>

# Same CID through a gateway you don't control
curl -s https://ipfs.io/ipfs/<metadata_cid>

You should get your JSON back, with a link to asset_cid inside it. The public AIOZ Pin gateway allows 15 requests per minute per CID, which is plenty for a check but not for a launch-day storefront. How to verify an NFT CID goes deeper on checking that the bytes match.

Step 4: Set the token URI (ERC-721 vs ERC-1155)

Use the ipfs:// scheme with the metadata CID, not a gateway URL. A gateway domain can change. The CID can't, and any gateway can resolve it. The function that returns the URI depends on your standard:

  • ERC-721 uses tokenURI(uint256 tokenId), usually one URI per token.
  • ERC-1155 uses uri(uint256 id). The URI may contain {id}, which clients replace with the token ID as 64 lowercase hex characters, with no 0x.

OpenSea's docs confirm it reads metadata from the URI that tokenURI or uri returns. Here's a sketch with OpenZeppelin Contracts 5.x storage extensions. It's not compiled here, and it leaves out access control, which you'd add before deploying:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {ERC721URIStorage} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import {ERC1155URIStorage} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol";

// ERC-721: tokenURI(tokenId) returns this string
contract Art721 is ERC721URIStorage {
    constructor() ERC721("Genesis", "GEN") {}
    function mint(address to, uint256 tokenId, string memory metadataURI) external {
        _safeMint(to, tokenId);
        _setTokenURI(tokenId, metadataURI); // "ipfs://<metadata_cid>"
    }
}

// ERC-1155: uri(id) returns this string
contract Art1155 is ERC1155URIStorage {
    constructor() ERC1155("") {}
    function mint(address to, uint256 id, string memory metadataURI) external {
        _mint(to, id, 1, "");
        _setURI(id, metadataURI); // "ipfs://<metadata_cid>"
    }
}

If your ERC-1155 collection uses one folder with {id} file names instead of a URI per token, the file names have to follow the 64-character hex rule exactly.

How do you pin a whole NFT collection?

For a collection, run the steps in batches: pin every asset and metadata pair, verify every CID, and only then send mint transactions. Don't alternate pin, mint, pin, mint. Catching ten failed pins before any mint is ten retries. Catching them after half the tokens are minted leaves you with a collection that's partly broken.

Mind the rate limits as you script it. The AIOZ Pin API allows 180 requests per minute, so a loop over 1,000 tokens should queue requests rather than fire them all at once. Automating NFT metadata pinning covers the batch code.

How AIOZ Pin handles NFT metadata

NFT Management is one of the three AIOZ Pin components. Each POST /api/nft/ call creates one NFT record that holds both CIDs, and you can list them with GET /api/nft/nfts/. If the asset is already on IPFS, the docs add an optional ?cid= query to reuse that asset CID instead of uploading it again.

Billing counts pinned files and storage like any other pin: the first 40,000 pinned files are free, and storage is $20 per TB per month. If each asset and each metadata JSON counts as one pinned file, a 10,000-piece collection is 20,000 files, inside the free count. The payment page doesn't say how NFT records are counted. How AIOZ Pin works has the full pricing.

Next step: read the AIOZ Pin ERC-1155 minting tutorial and the NFT API reference.

Frequently Asked Questions

How do I store NFT metadata on IPFS? Write the metadata JSON and pin it together with the asset through a pinning service. Verify that both CIDs load, then use ipfs://<metadata CID> as the token URI when you mint.

Should I pin the asset and metadata separately or together? Together. On AIOZ Pin, POST /api/nft/ or pinNft pins both in one request and returns both CIDs, so one can't persist without the other.

Does ERC-1155 use tokenURI? No. ERC-721 uses tokenURI(tokenId). ERC-1155 uses uri(id), and its URI can include an {id} placeholder that clients fill with the token ID in 64-character lowercase hex.

Can I edit NFT metadata after it's pinned? Not in place. Any change produces a new CID. You'd need to pin the new JSON and update the URI on chain, which many contracts don't allow after minting.

Should the token URI be ipfs:// or a gateway URL? Use ipfs://. Wallets and marketplaces resolve it through a gateway of their choice, and the URI keeps working if any one gateway goes away.

How do I confirm the pin succeeded before minting? Read the NFT record with GET /api/nft/{nftId} and check pinned, then fetch metadata_cid through at least one gateway.

References

We only send updates when meaningful changes ship, and you can unsubscribe anytime

Related Content

blog thumbnail

ERC-1155 Metadata on IPFS: The ID Substitution Rule

ERC-1155 metadata on IPFS breaks when filenames ignore the {id} rule. Here is the exact 64-character format, a working folder layout, and the per-token option.

6 min readOctober 21, 2026
blog thumbnail

AIOZ Pin Rate Limits: API, Public, and Premium Gateways

AIOZ Pin rate limits in one place: 180 requests per minute for the API, 15 per CID on the public gateway, and no predefined limit on premium gateways.

6 min readOctober 19, 2026
blog thumbnail

IPFS Pin Stuck on Pinning? What Each Pin Status Means

IPFS pin stuck on Pinning? Here is what Pinning, Pinned, and Failed mean on AIOZ Pin, why big directories can sit there, and how to read a pin's real state.

6 min readOctober 16, 2026
blog thumbnail

Why IPFS Used to Give You Different CIDs for the Same File

Two identical files, three IPFS tools, three different CIDs. Here is why that happened for years, and how IPIP-0499 made content addressing deterministic.

5 min readOctober 14, 2026
blog thumbnail

AIOZ Pin MCP Server Setup: llms.txt and 11 Tools Guide

AIOZ Pin MCP server setup has two paths: llms.txt lets a super intelligence assistant read the API, the MCP server lets it call 11 tools. Here is each one.

6 min readOctober 12, 2026
blog thumbnail

AIOZ Pin Pricing: The Complete Cost Breakdown

AIOZ Pin bills three flat rates against a token wallet, with no tiers to pick between. Here is what storage, bandwidth and pinned files cost, with examples.

5 min readOctober 09, 2026