Files
Upload file

Upload file

Upload a single file. The file is added to IPFS and pinned in the cluster.

Scope required: files:write


Endpoint

MethodPOST
URLhttps://api.pinarkive.com/api/v3/files
Content-Typemultipart/form-data

Headers: Authorization: Bearer YOUR_API_KEY or X-API-Key: YOUR_API_KEY

Body: Form field file (required). Optional: cl (cluster id), timelock (ISO 8601, premium only).


Request

cURL

curl -X POST https://api.pinarkive.com/api/v3/files \
  -H "X-API-Key: YOUR_API_KEY" \
  -F "file=@image.png"

With optional cluster and timelock (premium):

curl -X POST https://api.pinarkive.com/api/v3/files \
  -H "X-API-Key: YOUR_API_KEY" \
  -F "file=@document.pdf" \
  -F "cl=cl0-global" \
  -F "timelock=2026-12-31T23:59:59Z"

JavaScript (fetch)

const form = new FormData();
form.append("file", file);
 
const response = await fetch("https://api.pinarkive.com/api/v3/files", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.PINARKIVE_API_KEY,
  },
  body: form,
});
const data = await response.json();

JavaScript (axios)

const form = new FormData();
form.append("file", file);
 
const { data } = await axios.post(
  "https://api.pinarkive.com/api/v3/files",
  form,
  {
    headers: {
      "X-API-Key": process.env.PINARKIVE_API_KEY,
    },
  }
);

Python

import os
import requests
 
url = "https://api.pinarkive.com/api/v3/files"
headers = {"X-API-Key": os.environ["PINARKIVE_API_KEY"]}
files = {"file": open("image.png", "rb")}
data = {"cl": "cl0-global"}  # optional
 
r = requests.post(url, headers=headers, files=files, data=data)
r.raise_for_status()
print(r.json())

Go

package main
 
import (
	"bytes"
	"io"
	"mime/multipart"
	"net/http"
	"os"
)
 
func main() {
	url := "https://api.pinarkive.com/api/v3/files"
	apiKey := os.Getenv("PINARKIVE_API_KEY")
	var buf bytes.Buffer
	w := multipart.NewWriter(&buf)
	file, _ := os.Open("image.png")
	defer file.Close()
	part, _ := w.CreateFormFile("file", "image.png")
	io.Copy(part, file)
	w.WriteField("cl", "cl0-global")
	w.Close()
	req, _ := http.NewRequest("POST", url, &buf)
	req.Header.Set("X-API-Key", apiKey)
	req.Header.Set("Content-Type", w.FormDataContentType())
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}

PHP

<?php
$url = 'https://api.pinarkive.com/api/v3/files';
$apiKey = getenv('PINARKIVE_API_KEY');
$cfile = new CURLFile('image.png', 'image/png', 'image.png');
$post = ['file' => $cfile, 'cl' => 'cl0-global'];
 
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: ' . $apiKey]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);

Response

Success (200 / 201)

{
  "cid": "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
  "clusterId": "cl0-global",
  "expiresAt": "2026-12-31T23:59:59.000Z"
}
FieldTypeDescription
cidstringIPFS content identifier
clusterIdstringCluster where the file was pinned
expiresAtstring | nullExpiration (timelock), if set

Error (4xx / 5xx)

{
  "error": "Unauthorized",
  "message": "Invalid or missing API key",
  "code": "INVALID_API_KEY"
}

Common codes: 401 (invalid/missing key), 403 (plan limit, timelock on free plan, or code: missing_scope, required), 413 (file too large), 429 (rate limit; use retryAfter / Retry-After). See Error handling.