
IPFS content verification means your client hashes every block it receives and compares the result with the CID it asked for. A match proves the bytes are right, no matter who sent them. The Trustless Gateway spec brings that same check to plain HTTP.
TL;DR:
?format=raw) or a CAR stream (?format=car), and your client does the checking.Updated Oct 28, 2026: shorter answer-first opening, a verification diagram, a runnable hash check with its real output, the Trustless Gateway request formats from the spec, the verified-fetch library, and a closing AIOZ Pin section.
In IPFS, "trustless" has a narrow meaning. Anyone can still send you bad data, but you can always tell, because the check runs on your side and only needs the CID you started with.
Compare that with a normal URL. When you download https://example.com/report.pdf, you trust the server, its TLS certificate, and every cache in between to hand you the right file. With a CID, the address itself describes the content, so the sender's reputation stops mattering. A random peer, a public gateway, and your own server are all equally acceptable sources once you can verify what they return.
A CID has three parts: a version, a codec that says how to read the block, and a multihash. The multihash names the hash function, its length, and the digest. When a block arrives, your client runs the same hash function over the bytes and compares its digest with the one inside the CID.
You can see the whole idea in a few lines of standard-library Python. This script builds a CIDv1 for a raw block, the same way an IPFS node names a raw leaf, then checks the original bytes and a changed copy. We ran it on our machine. The CID it printed matches what the multiformats JavaScript library (9.9.0) produces for the same bytes.
import base64, hashlib
def cid_v1_raw(block: bytes) -> str:
# CIDv1 = version 0x01, codec raw 0x55, multihash sha2-256 (0x12, length 0x20, digest)
digest = hashlib.sha256(block).digest()
raw = bytes([0x01, 0x55, 0x12, 0x20]) + digest
return "b" + base64.b32encode(raw).decode().lower().rstrip("=")
block = b"hello from aioz pin\n"
cid = cid_v1_raw(block)
print("CID of the block: ", cid)
print("same bytes verify: ", cid_v1_raw(block) == cid)
print("one changed byte verify:", cid_v1_raw(b"hello from aioz pin!") == cid)CID of the block: bafkreiciuqus57wedvnzisfyydrze2ffnymhsgqafkwqx7kfh7cz72izbq
same bytes verify: True
one changed byte verify: FalseChanging one character gives a different digest, so the check fails. A real client does the same thing for every block, and it throws away any block that fails before the data reaches your app.

Most files are more than one block. IPFS stores them as a Merkle DAG, where each parent block lists the CIDs of its children. Once you have verified a parent, you also trust every child CID it lists, so each block can be checked as it streams in.
The same rule keeps directory checks cheap. To verify /photos/2026/cat.jpg inside a pinned folder of ten thousand files, you need the root block, the directory blocks along that path, and the blocks of cat.jpg. The other files never have to be downloaded. Unlike a textbook Merkle proof, which only carries sibling hashes, IPFS needs the full parent blocks on that path, but those are usually small.
The Trustless Gateway spec defines a small subset of the normal HTTP gateway. Its own summary says it lets light clients retrieve data behind a CID and verify its integrity "without delegating any trust to the gateway itself". Every response type is verifiable, and the gateway never decodes UnixFS files for you.
You choose between two response types with a query parameter or an Accept header:
?format=raw or Accept: application/vnd.ipld.raw. Only /ipfs/{cid} works here, with no path after the CID.?format=car or Accept: application/vnd.ipld.car. Paths are allowed, and the CAR includes the blocks you need to verify each path segment.CAR requests take a dag-scope parameter: block for just the final block, entity for everything needed to read one file or list one directory, and all, the default, for the whole DAG below the path. An entity-bytes=from:to parameter works like a verifiable HTTP range request. The two requests below follow the spec's format. We did not run them, so no output is shown.
curl -H "Accept: application/vnd.ipld.raw" "https://<gateway>/ipfs/<CID>" -o block.bin
curl "https://<gateway>/ipfs/<CID>/photos/cat.jpg?format=car&dag-scope=entity" -o cat.carAfter the download, you hash block.bin exactly as the script above does. For the CAR file, a library walks the blocks, checks each one, and rebuilds the file. Our guide to CAR files explains that format in detail.
When you paste https://<gateway>/ipfs/<CID> into a browser, the gateway fetches the blocks, checks them on its side, rebuilds the file, and sends you ordinary bytes. Your browser can't tell whether those bytes match the CID. That is fine for a quick look and for most web pages, as long as you trust the gateway operator.
If you want the check on your side without writing CAR parsing yourself, the Helia project ships @helia/verified-fetch. Its README describes a fetch-like API where "the integrity of all bytes are verified by comparing hashes of the data". It first tries providers that expose a trustless gateway and falls back to recursive gateways such as trustless-gateway.link. This is the README's getting-started example, which we did not run:
import { verifiedFetch } from '@helia/verified-fetch'
const resp = await verifiedFetch('ipfs://bafy...')Our post on Helia, the JavaScript IPFS implementation covers the rest of that toolkit.
A hash check answers one question: do these bytes match this CID? Three other questions stay open, and you should plan for each one.
AIOZ Pin's gateway docs describe the standard path format, https://gateway-url/ipfs/<CID>, with https://public.aiozpin.network/ipfs/{cid} as the public gateway and premium gateways for production traffic. Those are normal, trusted gateway requests. Our docs don't say whether AIOZ Pin's gateways answer ?format=raw or ?format=car requests.
You can still verify anything you serve from AIOZ Pin, because the CID comes from a source you trust: your own pin. The pin response and the pin details call both return the cid. Store it, then hash what your app downloads against it, or fetch through a verifying client. This is the documented call for one pin's details (not run here, no credentials on this machine):
curl --location --request GET 'https://api.aiozpin.network/api/pinning/<pinId>' \
--header 'pinning_api_key: KEY' \
--header 'pinning_secret_key: SECRET'Already have a CID from somewhere else? You can pin it by CID without re-uploading. The full request and response shapes are in the AIOZ Pin pinning API docs.
What does trustless mean in IPFS? It means your client checks each block by recomputing its hash and comparing it with the CID, so you don't have to trust the peer or gateway that sent it.
How does IPFS know a block was tampered with? The digest of the bytes you received won't match the digest inside the CID you requested, and the client rejects the block.
Do you need a whole directory to verify one file in it? No. You need the blocks on the path from the root CID to the file, plus the file's own blocks.
What is the difference between format=raw and format=car? format=raw returns one block for a bare CID. format=car returns a stream of blocks, allows a path, and lets you limit the scope with dag-scope.
Is a normal gateway URL verified? The gateway checks the blocks on its side, but your browser only receives the rebuilt file and can't check it against the CID.
Can I verify files served by AIOZ Pin? Yes. Keep the CID returned when you pin the file, then hash what you download against it or use a verifying client such as verified-fetch.
?format=car response returns
An IPFS dedicated gateway on AIOZ Pin is called a premium gateway. See what the free plan limits, what a paid plan adds, and what happens at zero balance.

Pin by CID asks a pinning service to fetch content already on IPFS and keep it. Covers the AIOZ Pin pinByHash call, statuses, and why a pin stalls on Pinning.

IPFS gateway not working? Read the status code first, then check the CID, your request rate, and whether anyone is providing the content. Here is the order.

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.

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.

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.