Back to blog

How To Upload To IPFS Using Python
While Pinata doesn’t offer an official Python SDK, a variety of community-built tools make it easy to upload content to IPFS using the language. But what if you want to write your own code without using a community SDK? Let’s do that together.
Getting Started
- Create a JWT from your Pinata API Keys Dashboard.
- Store it in an environment variable called
PINATA_JWT
.
export PINATA_JWT="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
- Install dependencies:
pip install requests tenacity python-dotenv
Uploading a File to IPFS via Pinata in Python
This script:
- Uses
multipart/form-data
as required by the API - Implements error handling and retries with exponential backoff
- Parses and validates responses
- Can be reused across projects
import os
import requests
from tenacity import retry, stop_after_attempt, wait_exponential
from dotenv import load_dotenv
# Load environment variables from a .env file
load_dotenv()
PINATA_JWT = os.getenv("PINATA_JWT")
if not PINATA_JWT:
raise EnvironmentError("Missing PINATA_JWT environment variable")
UPLOAD_URL = "<https://uploads.pinata.cloud/v3/files>"
HEADERS = {
"Authorization": f"Bearer {PINATA_JWT}"
}
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10))
def upload_file(filepath, name=None, keyvalues=None, group_id=None, network="private"):
if not os.path.isfile(filepath):
raise FileNotFoundError(f"File not found: {filepath}")
with open(filepath, "rb") as file_data:
files = {
"file": (os.path.basename(filepath), file_data)
}
data = {
"network": network
}
if name:
data["name"] = name
if group_id:
data["group_id"] = group_id
if keyvalues:
data["keyvalues"] = json.dumps(keyvalues) # must be stringified JSON
response = requests.post(
UPLOAD_URL,
headers=HEADERS,
files=files,
data=data,
timeout=30
)
if response.status_code != 200:
raise requests.HTTPError(f"Upload failed: {response.status_code} - {response.text}")
response_json = response.json()
if "data" not in response_json or "cid" not in response_json["data"]:
raise ValueError("Unexpected response format: 'cid' missing")
return response_json["data"]
# Example Usage
if __name__ == "__main__":
import json
try:
file_info = upload_file(
filepath="example.txt",
name="example.txt",
keyvalues={"category": "example"}
)
print("✅ Upload successful!")
print(f"📦 CID: {file_info['cid']}")
print(f"📄 Name: {file_info['name']}")
print(f"🕓 Created At: {file_info['created_at']}")
except Exception as e:
print(f"❌ Error uploading file: {e}")
Notes & Best Practices
- Use
requests
for simplicity and reliability. - Retries are handled by
tenacity
with exponential backoff. - Validate both the file path and response structure.
- The
keyvalues
dictionary can be used for searchable metadata. - Never hardcode JWTs — use environment variables and
.env
files.
Conclusion
While Pinata doesn’t (yet) have an official Python SDK, it’s very easy to work with IPFS + Pinata using Python. As we’ve seen more AI use cases over the last 6-12 months, Python has become an increasingly popular way to get files onto IPFS.