Pinata の Files API v3 でグループ機能を使用する際のはまりポイントと解決策をまとめます。

背景

Pinata でアップロードしたファイルをグループで管理し、特定のグループに属するファイルのみを取得したいケースがあります。例えば、NFT登録フォームで使用する入力画像を「input」グループに格納し、そのグループからのみ画像を選択できるようにする場合などです。

はまりポイント

1. レガシーAPI と V3 API のファイル管理は分離されている

問題 : レガシーAPI(pinFileToIPFS)でアップロードしたファイルは、V3 API(/v3/files)では取得できません。逆も同様です。

レガシーAPI (pinList)  →  レガシーでアップロードしたファイルのみ表示
V3 API (/v3/files)     →  V3でアップロードしたファイルのみ表示

解決策 : どちらかのAPIに統一する。V3 APIに移行する場合は、新規アップロードからV3を使用し、既存ファイルは手動でグループに追加するか、マイグレーションを検討。

2. V3 API のエンドポイントには {network} パラメータが必要

問題 : V3 API のエンドポイントは {network} パラメータ(public または private)が必須。

❌ GET /v3/files?group={group_id}
✅ GET /v3/files/public?group={group_id}

解決策 : 通常のIPFSファイルには public を使用。

3. グループフィルタのパラメータ名が異なる

問題 : アップロード時とリスト取得時でパラメータ名が異なる。

操作パラメータ名
アップロードgroup_id
リスト取得group

4. JWT の種類による認証の違い

問題 : Scoped Key で生成した JWT は V3 API で動作しない場合がある。

解決策 : Pinata ダッシュボードで Admin 権限を持つ新しい API Key を生成。

実装例

環境変数

# Pinata JWT (Admin権限推奨)
PINATA_JWT=eyJhbGciOiJIUzI1NiIs...

# グループID(Pinataダッシュボードで確認)
PINATA_INPUT_GROUP_ID=b6543372-dadd-482d-9409-98e9c2e079ff

アップロード API(V3)

// app/api/pinata/upload/route.ts
import { NextRequest, NextResponse } from "next/server";

const INPUT_GROUP_ID = process.env.PINATA_INPUT_GROUP_ID;

export async function POST(request: NextRequest) {
  const formData = await request.formData();
  const file = formData.get("file") as File;

  const pinataFormData = new FormData();
  pinataFormData.append("file", file);
  pinataFormData.append("name", file.name);
  pinataFormData.append("network", "public");        // 必須
  pinataFormData.append("group_id", INPUT_GROUP_ID); // グループに追加

  const response = await fetch(
    "https://uploads.pinata.cloud/v3/files",  // V3 アップロードエンドポイント
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.PINATA_JWT}`,
      },
      body: pinataFormData,
    }
  );

  const data = await response.json();
  return NextResponse.json({
    success: true,
    ipfsHash: data.data.cid,  // V3では data.data.cid
  });
}

リスト取得 API(V3)

// app/api/pinata/list/route.ts
import { NextRequest, NextResponse } from "next/server";

const INPUT_GROUP_ID = process.env.PINATA_INPUT_GROUP_ID;

export async function GET(request: NextRequest) {
  const limit = request.nextUrl.searchParams.get("limit") || "50";

  // V3 エンドポイント/public が必須
  const url = new URL("https://api.pinata.cloud/v3/files/public");
  url.searchParams.set("group", INPUT_GROUP_ID);  // group_id ではなく group
  url.searchParams.set("limit", limit);

  const response = await fetch(url.toString(), {
    method: "GET",
    headers: {
      Authorization: `Bearer ${process.env.PINATA_JWT}`,
    },
  });

  const data = await response.json();

  // V3 レスポンス構造
  const files = data.data?.files || [];

  return NextResponse.json({
    success: true,
    images: files.map((file) => ({
      ipfsHash: file.cid,
      name: file.name,
      datePinned: file.created_at,
      size: file.size,
    })),
  });
}

V3 API エンドポイント一覧

操作メソッドエンドポイント
ファイルアップロードPOSThttps://uploads.pinata.cloud/v3/files
ファイルリストGEThttps://api.pinata.cloud/v3/files/{network}
グループ作成POSThttps://api.pinata.cloud/v3/groups/{network}
グループにファイル追加PUThttps://api.pinata.cloud/v3/groups/{network}/{group_id}/ids/{file_id}

グループIDの確認方法

Pinata ダッシュボードでグループを選択すると、URLにグループIDが表示されます:

https://app.pinata.cloud/ipfs/groups/b6543372-dadd-482d-9409-98e9c2e079ff
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                      これがグループID

または、V3 API でファイルを取得すると、各ファイルの group_id フィールドで確認できます:

{
  "data": {
    "files": [
      {
        "id": "019b5f80-c298-7d6f-9ff0-58b2e16bfc38",
        "name": "example.jpg",
        "cid": "bafybei...",
        "group_id": "b6543372-dadd-482d-9409-98e9c2e079ff"
      }
    ]
  }
}

デバッグのコツ

  1. まずグループフィルタなしでリスト取得 : ファイルが存在するか確認
  2. レスポンスのgroup_id を確認: 期待するグループに属しているか確認
  3. エンドポイントURLを確認 : /public/private が含まれているか確認

まとめ

項目レガシーAPIV3 API
アップロードapi.pinata.cloud/pinning/pinFileToIPFSuploads.pinata.cloud/v3/files
リストapi.pinata.cloud/data/pinListapi.pinata.cloud/v3/files/{network}
グループパラメータ(アップロード)なしgroup_id
グループパラメータ(リスト)groupIdgroup
CIDの取得response.IpfsHashresponse.data.cid

V3 API への移行時は、これらの違いに注意して実装してください。