Skip to content

Pinning

Pin existing IPFS content to your account. When you pin a CID, our cluster fetches the content from the IPFS network and keeps it permanently available.

Pin by CID

POST /pin

Also available at POST /pins (IPFS Pinning Services API spec-compatible path — identical request and response):

bash
curl -X POST https://api.ipfs.ninja/pins \
  -H "X-Api-Key: bws_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"cid": "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"}'
ParameterTypeRequiredDescription
cidstringYesIPFS content identifier. Any form accepted: CIDv0 (Qm…), CIDv1 base32 (bafk…, bafy…, and other codecs).
descriptionstringNoShort description for your reference. Alias: name (matches the IPFS Pinning Services API field of the same name).
metadataobjectNoCustom key-value pairs to attach to the pin. Max 10 keys. Keys must be alphanumeric or underscore, 1-64 characters. Values must be strings, max 256 characters each. Total metadata size must not exceed 4 KB. Alias: meta (Pinning Services API).
multiaddressesstring[]NoOptional swarm-connect hints. Up to 5 libp2p multiaddresses of peers that host the CID. Our cluster runs swarm connect against each one in parallel before the pin, so content on private / non-DHT peers is reachable without waiting for DHT discovery. Best-effort — a failed connect does not fail the pin. See Pinning from a private node. Alias: origins (Pinning Services API).
folderIdstringNoDestination folder for the pinned row. Get folder IDs via GET /folders. Omit to land the pin at the root of your file list.

metadata.fileType (or meta.fileType) is a reserved metadata key: when set to one of the values listed under Automatic type detection, it overrides auto-detection once the pin resolves to pinned, instead of the byte-sniffed type. Auto-detection for pins works the same way as uploads — the actual content bytes are sniffed via a bounded range fetch rather than trusted from a gateway Content-Type header, which used to default to a generic binary label more often than it should have.

Pinning Services API field-name aliases

POST /pin accepts and returns name, meta, origins, created; GET /pin/:cid / GET /pins/:cid return only the name and created aliases on status lookups. These are the IPFS Pinning Services API spec's field names, so tooling built against that spec's naming works here too. POST /pin, GET /pin/:cid, and DELETE /pin/:cid are also reachable at POST /pins, GET /pins/:cid, and DELETE /pins/:cid — same integration, just the path the spec expects. We don't implement the full Pinning Services API surface (no queued status, no delegates, and the by-id lookup is keyed on cid rather than the spec's requestid) — just this path and field-name alignment.

Example request

bash
curl -X POST https://api.ipfs.ninja/pin \
  -H "X-Api-Key: bws_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "cid": "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
    "description": "NFT metadata",
    "metadata": {
      "collection": "my-nfts",
      "token_id": "42"
    }
  }'

Response 202 Accepted

json
{
  "cid": "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
  "status": "pinning",
  "description": "NFT metadata",
  "name": "NFT metadata",
  "meta": {
    "collection": "my-nfts",
    "token_id": "42"
  },
  "created": "2026-07-17T14:32:07.000Z",
  "uris": {
    "ipfs": "ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
    "url": "https://ipfs.ninja/ipfs/bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"
  }
}

For large DAGs (>500 blocks or >50 MB), the response includes an async: true flag:

json
{
  "cid": "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
  "status": "pinning",
  "async": true,
  "note": "Large DAG detected — pin running in background. Check status via GET /pin/bafybei…",
  "uris": { ... }
}

Pinning from a private node

If the CID you want to pin lives on a peer that isn't participating in the public DHT — a private staging node, a self-hosted machine on a VPN, or a workstation behind NAT — the default pin flow won't find it. Passing one or more multiaddresses tells our cluster exactly where to look.

We run ipfs swarm connect <multiaddr> for each hint in parallel before the pin runs. If the connect succeeds, the pin's DAG fetch can talk to your peer directly instead of hunting through the DHT. If it fails, the pin still proceeds against the public network (best-effort semantics).

Example: pin from a specific peer

bash
curl -X POST https://api.ipfs.ninja/pin \
  -H "X-Api-Key: bws_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "cid": "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
    "description": "internal staging build",
    "multiaddresses": [
      "/ip4/203.0.113.42/tcp/4001/p2p/12D3KooWH3uVF6wv47WnArKHk5p6cvgCJEb74UTmxztmQDc298L3",
      "/dns4/node.internal.example/tcp/443/wss/p2p/12D3KooWH3uVF6wv47WnArKHk5p6cvgCJEb74UTmxztmQDc298L3"
    ]
  }'

Response includes per-hint status

json
{
  "cid": "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
  "status": "pinning",
  "origins": [
    "/ip4/203.0.113.42/tcp/4001/p2p/12D3KooWH3uVF6wv47WnArKHk5p6cvgCJEb74UTmxztmQDc298L3",
    "/dns4/node.internal.example/tcp/443/wss/p2p/12D3KooWH3uVF6wv47WnArKHk5p6cvgCJEb74UTmxztmQDc298L3"
  ],
  "swarmConnected": [
    { "multiaddr": "/ip4/203.0.113.42/tcp/4001/p2p/12D3KooW…", "ok": true,  "strings": ["connect 12D3KooW… success"] },
    { "multiaddr": "/dns4/node.internal.example/tcp/443/…",   "ok": false, "error": "dial to peer: no route" }
  ],
  "info": {
    "swarmConnected": [
      { "multiaddr": "/ip4/203.0.113.42/tcp/4001/p2p/12D3KooW…", "ok": true,  "strings": ["connect 12D3KooW… success"] },
      { "multiaddr": "/dns4/node.internal.example/tcp/443/…",   "ok": false, "error": "dial to peer: no route" }
    ]
  },
  "uris": {  }
}

Accepted multiaddress shapes

Common shapes are supported: /ip4, /ip6, /dns4, /dns6, /dns, /dnsaddr transports; /tcp or /udp protocols; optional /quic-v1, /quic, /ws, /wss, /http, /https, /webtransport, /webrtc-direct upgrades. The multiaddress must end with /p2p/<peerId>. Cap: up to 5 hints per pin.

Getting your node's multiaddress

On the peer you want to pin from, run ipfs id and copy any of the Addresses entries that ends in /p2p/<PeerID>. Prefer public routable addresses (/ip4/YOUR_PUBLIC_IP/…) or DNS-based ones (/dnsaddr/your.domain/…) so our cluster can reach the peer from AWS.

Pinning very large directories

POST /pin is for content that already lives on the IPFS network — the cluster fetches the DAG block-by-block from peers, which can take several minutes for directories with 1,000+ files. During that fetch window, some child files may not yet be locally available and gateway requests to them may time out. Once the parent's status flips to pinned, every child is locally available and accessible via your gateway.

If you have the files locally (instead of just a CID), prefer CAR import for large NFT collections or datasets — it uploads the entire DAG to IPFS Ninja in one atomic request, so there's no fetch window and no partial-pin state. Create a CAR with:

bash
npx ipfs-car pack ./my-collection -o collection.car

Then import it via POST /upload/new with car: true.

TIP

Pinning is asynchronous. The response returns immediately with status pinning. Poll the status endpoint to check when pinning completes.

Check Pin Status

GET /pin/:cid

Also available at GET /pins/:cid (same response).

ParameterTypeRequiredDescription
cidstringYesThe CID you're checking.

Response 200 OK

json
{
  "cid": "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
  "status": "pinned",
  "sizeMB": 0.042,
  "fileName": "NFT metadata",
  "pinnedAt": 1711036800000,
  "name": "NFT metadata",
  "created": "2024-03-21T16:00:00.000Z",
  "info": {
    "sizeMB": 0.042,
    "fileName": "NFT metadata"
  },
  "uris": {
    "ipfs": "ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
    "url": "https://ipfs.ninja/ipfs/bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"
  }
}

Status values

StatusMeaning
pinningContent is being fetched from the IPFS network. Poll again in a few seconds.
pinnedContent is pinned and available through your account and gateway.
failedContent could not be found on the IPFS network. The CID may be invalid or the content is no longer available.

Delete a pin

DELETE /pin/:cid

Also available at DELETE /pins/:cid (same request and response).

Removes the file record for the CID from your account and decrements your storage usage. If the CID is a directory pin or a CAR upload, its child-file accounting rows are cleaned up too. The content is unpinned from the cluster only if no other IPFS Ninja user still holds the same CID — deleting your pin never affects another account's copy.

ParameterTypeRequiredDescription
cidstringYesThe CID to delete.

Example request

bash
curl -X DELETE https://api.ipfs.ninja/pin/bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi \
  -H "X-Api-Key: bws_your_api_key_here"

Response 200 OK

json
{
  "success": true,
  "cid": "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
  "sizeMBFreed": 0.042,
  "childFilesDeleted": 0,
  "clusterUnpin": "ok"
}

clusterUnpin reflects what happened on the IPFS cluster: ok (unpinned), not_pinned (already gone from the cluster), failed (the unpin attempt errored, but the file record was still deleted), or skipped_shared (another user still holds this CID, so the underlying content stays pinned).

Errors

StatusMeaning
404No file record for this CID under your account.

How pinning works

  1. You submit a CID via POST /pin
  2. Our IPFS cluster searches the network for nodes that have the content
  3. The cluster downloads and pins the content locally
  4. Once pinned, the file appears in your file list and is accessible via the gateway
  5. Storage usage is recorded when pinning completes

WARNING

Pinning time depends on file size and network availability. Small files typically pin in seconds. Large files or rarely-pinned content may take minutes.

Storage

Pinned content counts toward your plan's storage limit. The file size is recorded when pinning completes. If you approach your storage limit, you can free space by deleting unused files or upgrade for more capacity.