All API requests require a bearer token from https://app.pinata.cloud/developers/api-keys
POST /files
Headers:
Request Body (multipart/form-data):
Response Body:
{
"data": {
"id": "e5323ea7-8a02-4486-9b6f-63c788810aeb",
"name": "example.txt",
"cid": "bafkreicnu2aqjkoglrlrd65giwo4l64pdajxffk6jtq2vb7yaiopc3yu7m",
"size": 36,
"number_of_files": 1,
"mime_type": "text/plain",
"group_id": "18893556-de8e-4229-8a9a-27b95468dd3e",
"keyvalues": {
"category": "example"
},
"created_at": "2024-08-27T14:57:51.485934Z"
}
}
GET /files
Query Parameters:
Response Body:
{
"data": {
"files": [
{
"id": "e5323ea7-8a02-4486-9b6f-63c788810aeb",
"name": "example.txt",
"cid": "bafkreicnu2aqjkoglrlrd65giwo4l64pdajxffk6jtq2vb7yaiopc3yu7m",
"size": 36,
"number_of_files": 1,
"mime_type": "text/plain",
"group_id": "18893556-de8e-4229-8a9a-27b95468dd3e",
"keyvalues": {
"category": "example"
},
"created_at": "2024-08-27T14:57:51.485934Z"
}
],
"next_page_token": "MDE5MTk0NTctYzJjNi03NzBlLTkzOTEtOGM3MmM0ZjQxZjY0"
}
}
GET /files/{id}
Response Body:
{
"data": {
"id": "e5323ea7-8a02-4486-9b6f-63c788810aeb",
"name": "example.txt",
"cid": "bafkreicnu2aqjkoglrlrd65giwo4l64pdajxffk6jtq2vb7yaiopc3yu7m",
"size": 36,
"number_of_files": 1,
"mime_type": "text/plain",
"group_id": "18893556-de8e-4229-8a9a-27b95468dd3e",
"keyvalues": {
"category": "example"
},
"created_at": "2024-08-27T14:57:51.485934Z"
}
}
PUT /files/{id}
Request Body:
{
"name": "Updated Name",
"keyvalues": {
"category": "updated"
}
}
Response Body:
{
"data": {
"id": "e5323ea7-8a02-4486-9b6f-63c788810aeb",
"name": "Updated Name",
"cid": "bafkreicnu2aqjkoglrlrd65giwo4l64pdajxffk6jtq2vb7yaiopc3yu7m",
"size": 36,
"number_of_files": 1,
"mime_type": "text/plain",
"group_id": "18893556-de8e-4229-8a9a-27b95468dd3e",
"keyvalues": {
"category": "updated"
},
"created_at": "2024-08-27T14:57:51.485934Z"
}
}
DELETE /files/{id}
Response Body:
{
"data": null
}
Used for accessing private files
POST /files/sign
Request Body:
{
"url": "https://example.mypinata.cloud/files/bafybeifq444z4b7yqzcyz4a5gspb2rpyfcdxp3mrfpigmllh52ld5tyzwm",
"expires": 500000,
"date": 1724875300,
"method": "GET"
}
Response Body:
{
"data": "https://blush-fast-impala-660.mypinata.cloud/files/bafybeifq444z4b7yqzcyz4a5gspb2rpyfcdxp3mrfpigmllh52ld5tyzwm?X-Algorithm=PINATA1&X-Date=1724875300&X-Expires=500000&X-Method=GET&X-Signature=example-signature"
}
Groups are used for organizing files but also for optionally making files public
POST /files/groups
Request Body:
{
"name": "My Group",
"is_public": false
}
Response Body:
{
"data": {
"id": "01919976-955f-7d06-bd59-72e80743fb95",
"name": "My Group",
"is_public": false,
"created_at": "2024-08-28T14:49:31.246596Z"
}
}
GET /files/groups
Query Parameters:
Response Body:
{
"data": {
"groups": [
{
"id": "01919976-955f-7d06-bd59-72e80743fb95",
"name": "My Group",
"is_public": false,
"created_at": "2024-08-28T14:49:31.246596Z"
}
],
"next_page_token": "MDE5MTk5NzYtOTU1Zi03ZDA2LWJkNTktNzJlODA3NDNmYjk1"
}
}
GET /files/groups/{id}
Response Body:
{
"data": {
"id": "01919976-955f-7d06-bd59-72e80743fb95",
"name": "My Group",
"is_public": false,
"created_at": "2024-08-28T14:49:31.246596Z"
}
}
PUT /files/groups/{id}
Request Body:
{
"name": "Updated Name",
"is_public": true
}
Response Body:
{
"data": {
"id": "01919976-955f-7d06-bd59-72e80743fb95",
"name": "Updated Name",
"is_public": true,
"created_at": "2024-08-28T14:49:31.246596Z"
}
}
DELETE /files/groups/{id}
Response Body:
{
"data": null
}
PUT /files/groups/{id}/ids/{file_id}
Response Body:
{
"data": null
}
DELETE /files/groups/{id}/ids/{file_id}
Response Body:
{
"data": null
}
PUT /files/swap/{cid}
Request Body:
{
"swap_cid": "bafkreig4zcnmqa23zff3ye7tuef6wrlq3aimffzm22axfeh3ddmawzlzz4"
}
Response Body:
{
"data": {
"mapped_cid": "bafkreig4zcnmqa23zff3ye7tuef6wrlq3aimffzm22axfeh3ddmawzlzz4",
"created_at": "2024-09-20T17:09:39.490275Z"
}
}
GET /files/swap/{cid}
Query Parameters:
Response Body:
{
"data": [
{
"mapped_cid": "bafkreig4zcnmqa23zff3ye7tuef6wrlq3aimffzm22axfeh3ddmawzlzz4",
"created_at": "2024-09-20T17:09:39.490275Z"
}
]
}
DELETE /files/swap/{cid}
Response Body:
{
"data": null
}
POST /pinata/keys
Create a new API key with specific permissions.
Request Body:
{
"keyName": "My API Key",
"permissions": {
"admin": false,
"endpoints": {
"data": {
"pinList": true,
"userPinnedDataTotal": true
},
"pinning": {
"hashMetadata": true,
"hashPinPolicy": true,
"pinByHash": true,
"pinFileToIPFS": true,
"pinJSONToIPFS": true,
"pinJobs": true,
"unpin": true,
"userPinPolicy": true
}
}
},
"maxUses": 100
}
Response:
{
"JWT": "jwt-token",
"pinata_api_key": "key",
"pinata_api_secret": "secret"
}
GET /pinata/keys
Query Parameters:
Response:
{
"keys": [
{
"id": "d4ea5a38-4e0a-4126-8fd4-7534d258a995",
"name": "My API Key",
"key": "6270c5f4ed520756d498effbb6eb4b5f",
"secret": "secretkey",
"max_uses": 2,
"uses": 2,
"user_id": "32bd7147-51d5-4df2-8771-7aeb9dcac7a2",
"scopes": {
"endpoints": {
"pinning": {
"pinFileToIPFS": true,
"pinJSONToIPFS": true
}
},
"admin": false
},
"revoked": true,
"createdAt": "2024-06-12T15:34:50.324Z",
"updatedAt": "2024-06-12T15:34:51.204Z"
}
],
"count": 1
}
PUT /pinata/keys/{key}
Parameters:
Response: “Revoked”
The API uses standard HTTP response codes:
Remember to handle errors appropriately and implement retries for network failures. Always use environment variables for API keys and validate inputs before making API calls.
Install from npm:
npm i pinata
Import with either module or commonjs:
import { PinataSDK } from "pinata"
// or
const { PinataSDK } = require("pinata")
const pinata = new PinataSDK({
pinataJwt: string, // Required JWT token
pinataGateway?: string, // Optional gateway domain
customHeaders?: Record<string, string>,
});
Response:
type PinataConfig = {
pinataJwt: string;
pinataGateway?: string;
customHeaders?: Record<string, string>;
}
// Single file upload
pinata.upload.file(File)
.group(groupId) // Optional
.addMetadata({ // Optional
name: string,
keyvalues: Record<string, string>
})
.key(apiKey) // Optional
Response:
type UploadResponse = {
id: string;
name: string;
cid: string;
size: number;
number_of_files: number;
mime_type: string;
user_id: string;
group_id: string | null;
}
// Multiple files
pinata.upload.fileArray([File, File, ...])
// JSON content
pinata.upload.json(JsonObject)
// Base64 content
pinata.upload.base64(string)
// URL content
pinata.upload.url(string)
// List files
pinata.files.list()
.name(string) // Filter by name
.group(string) // Filter by group
.noGroup(boolean) // Filter ungrouped
.cid(string) // Filter by CID
.metadata(Record<string, string>) // Filter by metadata
.mimeType(string) // Filter by type
.order("ASC"|"DESC") // Sort order
.limit(number) // Results limit
.cidPending(boolean) // Filter pending
.pageToken(string) // Pagination
Response:
type FileListResponse = {
files: FileListItem[];
next_page_token: string;
}
// Delete files
pinata.files.delete([fileId, fileId, ...])
Response:
type DeleteResponse = {
id: string;
status: string;
}[]
// Update file
pinata.files.update({
id: string,
name?: string
})
Response:
type FileListItem = {
id: string;
name: string | null;
cid: string;
size: number;
number_of_files: number;
mime_type: string;
group_id: string | null;
created_at: string;
}
pinata.files.addSwap({
cid: string,
swapCid: string
})
Response:
type SwapCidResponse = {
mapped_cid: string;
created_at: string;
}
pinata.files.deleteSwap(cid)
Response: null
pinata.files.getSwapHistory({
cid: string,
domain: string
})
Response: SwapCidResponse[]
// Retrieve file
pinata.gateways.get(cid)
.optimizeImage({ // Optional image optimization
width?: number,
height?: number,
format?: "auto"|"webp",
// ... other options
})
Response:
type GetCIDResponse = {
data?: JSON | string | Blob | null;
contentType: ContentType;
}
// Create signed URL
pinata.gateways.createSignedURL({
cid: string,
expires: number,
date?: number,
gateway?: string
})
Response: string
// Create group
pinata.groups.create({
name: string,
isPublic?: boolean
})
Response:
type GroupResponseItem = {
id: string;
is_public: boolean;
name: string;
created_at: string;
}
// List groups
pinata.groups.list()
.name(string)
.isPublic(boolean)
.limit(number)
.pageToken(string)
Response:
type GroupListResponse = {
groups: GroupResponseItem[];
next_page_token: string;
}
// Get group
pinata.groups.get({groupId: string})
Response: GroupResponseItem
// Update group
pinata.groups.update({
groupId: string,
name?: string,
isPublic?: boolean
})
Response: GroupResponseItem
// Delete group
pinata.groups.delete({groupId: string})
Response: null
// Manage files in group
pinata.groups.addFiles({
groupId: string,
files: string[]
})
Response:
type UpdateGroupFilesResponse = {
id: string;
status: string;
}[]
pinata.groups.removeFiles({
groupId: string,
files: string[]
})
Response: Same as addFiles
// Create key
pinata.keys.create({
keyName: string,
permissions: {
admin?: boolean,
endpoints?: {
data?: {
pinList?: boolean,
userPinnedDataTotal?: boolean
},
pinning?: {
pinFileToIPFS?: boolean,
pinJSONToIPFS?: boolean,
// ... other permissions
}
}
},
maxUses?: number
})
Response:
type KeyResponse = {
JWT: string;
pinata_api_key: string;
pinata_api_secret: string;
}
// List keys
pinata.keys.list()
.name(string)
.revoked(boolean)
.exhausted(boolean)
.offset(number)
Response:
type KeyListResponse = {
keys: KeyListItem[];
count: number;
}
// Revoke keys
pinata.keys.revoke([keyString, keyString, ...])
Response:
type RevokeKeyResponse = {
key: string;
status: string;
}[]
pinata.testAuthentication()
Response:
type AuthTestResponse = {
message: string;
}
Remember these key implementation details:
When helping developers: