
Pinning an ERC-8004 Registration File to IPFS is the part of setting up an AI agent's on-chain identity that has nothing to do with Solidity or a wallet, it's a JSON file and a pin operation, the same workflow this blog has already covered for NFT metadata. This walks through building the file, pinning it with AIOZ Pin, verifying the pin resolved, and pointing the Identity Registry's register() call at the result.
TL;DR:
type, name, description, services, x402Support, active)pinFilesToIPFS() from the AIOZ Pin Node.js SDKgetPinByCID() before using it anywhereregister(agentURI, metadata) with agentURI set to ipfs://{cid}Start with the JSON document itself, following ERC-8004's defined schema:
{
"type": "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
"name": "Research Assistant Agent",
"description": "An agent that summarizes and cross-references academic papers",
"image": "ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
"services": [
{ "type": "A2A", "endpoint": "https://agent.example.com/a2a" }
],
"x402Support": true,
"active": true,
"registrations": []
}
Save this as a local file, registration.json, before moving to the pinning step. The registrations array stays empty until after you've actually called register() on-chain, since it needs the agentId that call returns, you'll come back and update this file with a second pin once you have it.
A Registration File that's syntactically valid JSON but missing a field the Identity Registry or a client expects, services as a string instead of an array, active omitted entirely, still pins successfully. Nothing about the pinning step checks the content against ERC-8004's schema, it's just a file as far as AIOZ Pin is concerned, covered in more detail in this series' overview of the specification. Catching a structural mistake before it's pinned and referenced on-chain is cheap: run the JSON through a linter or a quick schema check locally, JSON.parse() the file and verify the required fields (type, name, services) are present with the right types, before calling pinFilesToIPFS(). A malformed file that's already pinned and registered isn't unfixable, step 5 below covers updating it, but catching the mistake before spending gas on register() is strictly cheaper than after.
import AiozPinClient from '@aioznetwork/aioz-pin-sdk'
import fs from 'fs'
const client = new AiozPinClient('your-api-key', 'your-secret-key')
const result = await client.pinFilesToIPFS({
filePaths: ['./registration.json'],
options: {
name: 'agent-registration-v1',
keyvalues: { agentName: 'Research Assistant Agent' }
}
})
console.log(result.cid)
This is the exact same pinFilesToIPFS() method covered for general file pinning, a Registration File is just a JSON file as far as the pinning layer is concerned. The keyvalues metadata is optional but useful if you're managing pins for multiple agents and want to filter by agent name later through getPinList().
const pin = await client.getPinByCID(result.cid)
console.log(pin.status)
Don't skip this before wiring the CID into an on-chain transaction. A pin that's still processing or failed silently is a much cheaper problem to catch here than after you've spent gas registering a broken agentURI.
It's worth being clear about what pinning the Registration File does and doesn't guarantee at this stage. AIOZ Pin keeps the file's blocks online and replicated, covered in full in how AIOZ Pin actually keeps files online, so the CID stays resolvable as long as the pin remains active. What it doesn't do is put the file itself on-chain, the ipfs://{cid} reference stored in the Identity Registry is a pointer, not the document, the same relationship this blog covers for NFT metadata generally. If the pin is ever removed and no other peer independently holds the same content, the on-chain agentId still exists and resolves to a valid transaction, but the Registration File it points at stops being retrievable, which is exactly why treating this as infrastructure to actively maintain, not a one-time upload, matters for anything meant to represent a persistent agent identity.
This step happens outside AIOZ Pin, through whatever web3 library your project already uses (ethers.js, viem, or similar) to call the Identity Registry contract's register() function:
const agentURI = `ipfs://${result.cid}`
const tx = await identityRegistry.register(agentURI, [])
const receipt = await tx.wait()
// the returned agentId is available in the transaction receipt's emitted event
AIOZ Pin's role ends at producing a working ipfs://{cid} reference, the actual on-chain registration is a standard contract call against whatever address hosts the Identity Registry you're using, not something AIOZ Pin's tooling handles directly.
If you want the Registration File itself to reference its own on-chain registration, update the registrations array with the agentId and registry address from step 4, then pin the updated file the same way as step 2. This produces a new CID, since changing the content changes the CID, so you'd call setAgentURI() on the Identity Registry to point at the updated file if you take this step.
What method do I use to pin an ERC-8004 Registration File? pinFilesToIPFS() from the AIOZ Pin Node.js SDK, the same method used for pinning any file, a Registration File is just a JSON document at the pinning layer.
Do I need to verify the pin before using the CID? Yes. Call getPinByCID() to confirm the pin resolved before referencing it in an on-chain register() transaction, catching a failed pin here is far cheaper than after spending gas on a broken reference.
Does AIOZ Pin handle the on-chain agent registration too? No. AIOZ Pin pins the Registration File and gives you a CID. The actual register() call to the Identity Registry contract happens through a separate web3 library like ethers.js or viem.
What goes in the registrations array of a Registration File? The agentId and registry address once you've completed on-chain registration. It's fine to leave this empty for the first pin, since you need the on-chain agentId before you can fill it in.
Can I update a Registration File after it's pinned? Not in place. Since a CID is derived from the file's content, any change produces a new CID. Pin the updated file separately, then call setAgentURI() on the Identity Registry to point at the new CID.
pinFilesToIPFS() reference used in step 2
IPFS defaults to 256 KiB fixed-size chunks, but also ships Rabin and Buzhash content-defined chunkers. Here is why the choice affects deduplication.

An IPFS CID is not a random string. It encodes a version, a codec, and a hash algorithm plus digest. Here is how to decode a real CID piece by piece.

IPFS does not use a B-tree for large directories. It uses a HAMT, a Hash Array Mapped Trie. Here is exactly how it shards a folder once it outgrows one block.

AIOZ Pin image resizing happens straight in the gateway URL, no upload step or separate service. Here is every img- parameter, with real srcset examples.

x402 payments let ERC-8004 weight a paid AI agent interaction more heavily than free work in its reputation score. Here is exactly how that link works.

AIOZ Pin NFT API calls pin an asset and its metadata as two tracked pins under one record. Here is how to automate it directly over REST, no SDK needed.