· Nacho Coll · Tutorials · 10 min de citit
IPFS Upload API — Tutorial complet pentru dezvoltatori
Învață să încarci fișiere pe IPFS prin REST API. Exemple complete de cod în JavaScript, Node.js și curl. Încarcă JSON, imagini, folosește tokenuri semnate pentru încărcări din client.

IPFS Upload API — Tutorial complet pentru dezvoltatori
Încărcarea fișierelor pe IPFS ar trebui să fie la fel de simplă ca trimiterea unei cereri POST. În acest tutorial vei face exact asta — vei încărca documente JSON, imagini și PDF-uri pe IPFS folosind doar fetch() și o cheie API. La final vei avea un script Node.js complet care încarcă conținut, listează fișiere, recuperează metadate și generează tokenuri semnate pentru încărcări sigure din partea clientului. Nou în IPFS? Începe cu Ce este IPFS Pinning? pentru a înțelege bazele înainte de a intra în cod.

Ce vei construi
- Încarcă un obiect JSON pe IPFS și primește înapoi un identificator de conținut (CID).
- Încarcă o imagine binară de pe disc.
- Atașează descrieri și metadate personalizate la încărcări.
- Interoghează istoricul încărcărilor după interval de date.
- Recuperează detalii pentru un fișier specific.
- Creează tokenuri semnate cu durată limitată pentru ca un browser să poată încărca direct fără a expune cheia API.
- Gestionează erorile și implementează logică de reîncercare.
Totul rulează pe un singur URL de bază: https://api.ipfs.ninja
1. Configurare — Înregistrare și obținerea unei chei API
- Înregistrează-te pentru un cont gratuit (nu este necesar card de credit).
- Mergi la API Keys în bara laterală a dashboardului.
- Apasă Create key, dă-i un nume și copiază cheia imediat — nu va mai fi afișată din nou.

Cheia ta arată ca bws_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6. Toate exemplele de mai jos o trimit în antetul X-Api-Key.
2. Încarcă JSON pe IPFS
Cea mai simplă încărcare: pasează un obiect JavaScript simplu ca content, iar API-ul îl serializează, îl pinează pe IPFS și returnează CID-ul.
// upload-json.mjs
const API = "https://api.ipfs.ninja";
const API_KEY = "bws_your_key_here";
const payload = {
content: {
name: "Galactic Badge #42",
description: "Proof of attendance — Galactic Meetup 2026",
attributes: [
{ trait_type: "Event", value: "Galactic Meetup" },
{ trait_type: "Year", value: 2026 }
]
}
};
const res = await fetch(`${API}/upload/new`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": API_KEY
},
body: JSON.stringify(payload)
});
const data = await res.json();
console.log("CID :", data.cid);
console.log("Size:", data.sizeMB, "MB");
console.log("IPFS:", data.uris.ipfs);
console.log("URL :", data.uris.url);Rulează cu node upload-json.mjs. Un răspuns reușit arată astfel:
{
"cid": "bafkreigx7gq...",
"sizeMB": 0.0004,
"uris": {
"ipfs": "ipfs://bafkreigx7gq...",
"url": "https://ipfs.ninja/ipfs/bafkreigx7gq..."
}
}Câmpul url indică o poartă HTTP publică, așa că conținutul este imediat accesibil în orice browser.
3. Încarcă o imagine
Fișierele binare (imagini, PDF-uri, audio) sunt trimise ca șiruri codificate în base64 în câmpul content.
// upload-image.mjs
import { readFileSync } from "node:fs";
const API = "https://api.ipfs.ninja";
const API_KEY = "bws_your_key_here";
const imageBuffer = readFileSync("./photo.png");
const base64 = imageBuffer.toString("base64");
const res = await fetch(`${API}/upload/new`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": API_KEY
},
body: JSON.stringify({ content: base64 })
});
const data = await res.json();
console.log("Image CID:", data.cid);
console.log("Gateway :", data.uris.url);API-ul detectează automat tipul MIME — PNG, JPEG, WebP, GIF și PDF sunt toate suportate. Nu sunt necesare antete suplimentare sau suprascrieri de content-type.
Cu curl, aceeași operațiune arată astfel:
BASE64=$(base64 -w 0 photo.png)
curl -X POST https://api.ipfs.ninja/upload/new \
-H "Content-Type: application/json" \
-H "X-Api-Key: bws_your_key_here" \
-d "{\"content\": \"$BASE64\"}"4. Încărcare cu metadate
Fiecare încărcare acceptă două câmpuri opționale: description (etichetă de text liber) și metadata (perechi cheie-valoare arbitrare). Ambele sunt stocate alături de CID și returnate atunci când listezi sau aduci fișierul mai târziu.
// upload-with-metadata.mjs
const API = "https://api.ipfs.ninja";
const API_KEY = "bws_your_key_here";
const res = await fetch(`${API}/upload/new`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": API_KEY
},
body: JSON.stringify({
content: { title: "Meeting Notes", body: "Q1 roadmap recap..." },
description: "Q1 2026 planning meeting notes",
metadata: {
project: "acme-app",
author: "dana",
version: "1"
}
})
});
const data = await res.json();
console.log("CID:", data.cid);Metadatele facilitează filtrarea și organizarea fișierelor de partea ta fără a analiza conținutul IPFS în sine.
5. Pinează un CID existent
Dacă ai deja conținut pe IPFS și vrei să te asiguri că rămâne disponibil, pinează-l după CID:
// pin-cid.mjs
const API = "https://api.ipfs.ninja";
const API_KEY = "bws_your_key_here";
const res = await fetch(`${API}/pin`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": API_KEY
},
body: JSON.stringify({
cid: "bafkreigx7gq...",
description: "Pinned from external source"
})
});
const data = await res.json();
console.log("Pinned:", data.cid);6. Listează fișierele tale
Recuperează fiecare fișier pe care l-ai încărcat într-o anumită fereastră de timp. Parametrii de interogare from și to sunt timestampuri Unix în milisecunde.
// list-files.mjs
const API = "https://api.ipfs.ninja";
const API_KEY = "bws_your_key_here";
const now = Date.now();
const oneWeekAgo = now - 7 * 24 * 60 * 60 * 1000;
const url = `${API}/upload/list?from=${oneWeekAgo}&to=${now}`;
const res = await fetch(url, {
headers: { "X-Api-Key": API_KEY }
});
const files = await res.json();
for (const file of files) {
console.log(`${file.cid} ${file.description ?? "(no description)"}`);
}Cu curl:
FROM=$(($(date +%s) * 1000 - 604800000))
TO=$(($(date +%s) * 1000))
curl -s "https://api.ipfs.ninja/upload/list?from=$FROM&to=$TO" \
-H "X-Api-Key: bws_your_key_here" | jq .7. Obține detaliile fișierului
Recuperează înregistrarea completă pentru un singur CID, inclusiv metadate, dimensiune și timestampuri:
// get-file.mjs
const API = "https://api.ipfs.ninja";
const API_KEY = "bws_your_key_here";
const CID = "bafkreigx7gq...";
const res = await fetch(`${API}/file/${CID}`, {
headers: { "X-Api-Key": API_KEY }
});
const details = await res.json();
console.log(JSON.stringify(details, null, 2));8. Încărcări din client cu tokenuri semnate
Includerea unei chei API într-un bundle de browser este un risc de securitate. În schimb, generează un token semnat cu durată scurtă pe server și pasează-l clientului.
Server (Express)
// server.mjs
import express from "express";
const app = express();
const API = "https://api.ipfs.ninja";
const API_KEY = process.env.IPFS_API_KEY;
app.post("/api/upload-token", async (req, res) => {
const response = await fetch(`${API}/upload/signed-url`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": API_KEY
},
body: JSON.stringify({
name: "browser-upload",
expiresIn: 600 // token valid for 10 minutes
})
});
const { token, tokenId, expiresAt } = await response.json();
res.json({ token, tokenId, expiresAt });
});
app.listen(3000, () => console.log("Server running on :3000"));Client în browser
<!-- upload.html -->
<input type="file" id="filePicker" />
<button id="uploadBtn">Upload to IPFS</button>
<pre id="result"></pre>
<script>
const API = "https://api.ipfs.ninja";
document.getElementById("uploadBtn").addEventListener("click", async () => {
// 1. Get a signed token from your own backend
const tokenRes = await fetch("/api/upload-token", { method: "POST" });
const { token } = await tokenRes.json();
// 2. Read the selected file as base64
const file = document.getElementById("filePicker").files[0];
if (!file) return alert("Pick a file first");
const base64 = await new Promise((resolve) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result.split(",")[1]);
reader.readAsDataURL(file);
});
// 3. Upload directly to IPFS using the signed token
const uploadRes = await fetch(`${API}/upload/new`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Signed ${token}`
},
body: JSON.stringify({
content: base64,
description: file.name
})
});
const data = await uploadRes.json();
document.getElementById("result").textContent = JSON.stringify(data, null, 2);
});
</script>Browserul nu vede niciodată cheia ta API. Tokenul semnat expiră automat. Tokenurile sunt cu utilizare multiplă — pot fi folosite de mai multe ori până expiră sau sunt revocate. useCount este urmărit, dar nu este aplicat ca limită.
9. Gestionarea erorilor
API-ul folosește coduri de stare HTTP convenționale. Iată cele pe care ar trebui să le gestionezi explicit:
| Status | Semnificație | Ce trebuie făcut |
|---|---|---|
| 400 | Bad request — câmpuri lipsă sau invalide | Verifică dacă content este prezent și valid |
| 401 | Unauthorized — cheie API incorectă sau lipsă | Verifică antetul X-Api-Key |
| 413 | Payload too large | Redu dimensiunea fișierului sau împarte conținutul |
| 429 | Rate limited | Așteaptă și reîncearcă cu întârziere exponențială |
| 500 | Server error | Reîncearcă după o scurtă întârziere |
O funcție de încărcare rezistentă cu backoff exponențial:
// resilient-upload.mjs
const API = "https://api.ipfs.ninja";
const API_KEY = "bws_your_key_here";
async function uploadWithRetry(content, retries = 3) {
for (let attempt = 1; attempt <= retries; attempt++) {
const res = await fetch(`${API}/upload/new`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": API_KEY
},
body: JSON.stringify({ content })
});
if (res.ok) return await res.json();
const body = await res.text();
if (res.status === 401) {
throw new Error(`Authentication failed: ${body}`);
}
if (res.status === 413) {
throw new Error(`Payload too large — reduce file size. ${body}`);
}
if (res.status === 429 || res.status >= 500) {
const delay = Math.pow(2, attempt) * 1000; // 2s, 4s, 8s
console.warn(`Attempt ${attempt} failed (${res.status}). Retrying in ${delay}ms...`);
await new Promise((r) => setTimeout(r, delay));
continue;
}
throw new Error(`Upload failed (${res.status}): ${body}`);
}
throw new Error("Upload failed after all retries");
}
// Usage
const data = await uploadWithRetry({ hello: "world" });
console.log("CID:", data.cid);10. Exemplu complet de lucru
Un singur script care exersează fiecare endpoint acoperit în acest tutorial. Salvează-l ca ipfs-demo.mjs și rulează cu node ipfs-demo.mjs.
// ipfs-demo.mjs
import { readFileSync } from "node:fs";
const API = "https://api.ipfs.ninja";
const API_KEY = "bws_your_key_here";
const headers = {
"Content-Type": "application/json",
"X-Api-Key": API_KEY
};
async function request(method, path, body) {
const opts = { method, headers };
if (body) opts.body = JSON.stringify(body);
const res = await fetch(`${API}${path}`, opts);
if (!res.ok) throw new Error(`${method} ${path} → ${res.status}: ${await res.text()}`);
return res.json();
}
// --- 1. Upload JSON ---
console.log("--- Upload JSON ---");
const jsonResult = await request("POST", "/upload/new", {
content: { name: "Demo Token", edition: 1 },
description: "Tutorial demo — JSON upload",
metadata: { tutorial: "true" }
});
console.log("CID:", jsonResult.cid);
console.log("URL:", jsonResult.uris.url);
// --- 2. Upload an image (if photo.png exists) ---
try {
const img = readFileSync("./photo.png");
console.log("\n--- Upload Image ---");
const imgResult = await request("POST", "/upload/new", {
content: img.toString("base64"),
description: "Tutorial demo — image upload"
});
console.log("CID:", imgResult.cid);
console.log("URL:", imgResult.uris.url);
} catch {
console.log("\n--- Skipping image upload (no photo.png found) ---");
}
// --- 3. Pin the JSON CID ---
console.log("\n--- Pin CID ---");
const pinResult = await request("POST", "/pin", {
cid: jsonResult.cid,
description: "Pinned from tutorial"
});
console.log("Pinned:", pinResult.cid);
// --- 4. Get file details ---
console.log("\n--- File Details ---");
const details = await request("GET", `/file/${jsonResult.cid}`);
console.log(JSON.stringify(details, null, 2));
// --- 5. List recent files ---
console.log("\n--- Recent Files ---");
const now = Date.now();
const oneHourAgo = now - 60 * 60 * 1000;
const files = await request("GET", `/upload/list?from=${oneHourAgo}&to=${now}`);
console.log(`Found ${files.length} file(s) in the last hour`);
for (const f of files) {
console.log(` - ${f.cid} ${f.description ?? ""}`);
}
// --- 6. Create a signed upload token ---
console.log("\n--- Signed Token ---");
const tokenResult = await request("POST", "/upload/signed-url", {
name: "demo-token",
expiresIn: 300
});
console.log("Token ID :", tokenResult.tokenId);
console.log("Expires :", new Date(tokenResult.expiresAt).toISOString());
// --- 7. Upload using the signed token ---
console.log("\n--- Upload with Signed Token ---");
const signedRes = await fetch(`${API}/upload/new`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Signed ${tokenResult.token}`
},
body: JSON.stringify({
content: { note: "Uploaded with a signed token" }
})
});
const signedData = await signedRes.json();
console.log("CID:", signedData.cid);
console.log("\nDone.");Înlocuiește bws_your_key_here cu o cheie reală și rulează scriptul. Fiecare pas își afișează rezultatul ca să poți urmări.
11. Pașii următori
Acum știi cum să încarci, să pinezi, să listezi și să recuperezi fișiere prin IPFS Upload API și cum să păstrezi în siguranță încărcările din browser cu tokenuri semnate. Pentru o privire mai amplă, inclusiv interfața dashboardului și exemple Python, consultă Cum să încarci fișiere pe IPFS. Iată unde să mergi de aici:
- API Reference — Documentație completă a endpointurilor la ipfs.ninja/docs.
- Porți personalizate — Servește conținut IPFS din propriul domeniu. Vezi ghidul de configurare a porții.
- Analitică — Urmărește volumul de încărcare, lățimea de bandă și numărul de pinări în dashboard.
- Client HTTP — Nu este necesar niciun SDK. Poți folosi
fetch()standard sau orice client HTTP pentru a interacționa cu API-ul.
Dacă întâmpini probleme, deschide un tichet la support.ipfs.ninja sau alătură-te comunității pe Discord.
