Pinion Documentation

Quick Start Guide

Get started with Pinion in three simple steps:

1

Get Your API Token

Sign in to your Dashboard and navigate to your profile settings to create an API token. Keep it secure!

2

Choose Your Tool

Use curl for quick tests, or install an IPFS pinning service client library for your language of choice.

3

Make Your First Pin

Try pinning content with a simple curl command:

curl -X POST https://<environment>.pinion.build/pinning/api/v1/pins \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"cid": "bafybeigdyrzt...", "name": "my-first-pin"}'

Pinning Service

IPFS Pinning Service API Documentation

Overview

The Pinning Service API allows you to manage and persist content on IPFS by "pinning" CID objects. Pinning ensures that specific data remains available and is not garbage-collected by IPFS nodes.

This API is compatible with the IPFS Pinning Service API specification v1.0.0.

Base URL

https://<environment>.pinion.build/pinning/api/v1

Authentication

All endpoints require authentication using a Bearer token.

Example
Authorization: Bearer <API_TOKEN>

To create or manage API tokens, visit your Account Settings.

Endpoints

List Pins
GET /pins

Retrieve a list of pinned or pinning requests.

Query Parameters
NameTypeDescription
cidstringFilter by specific CID (exact match or comma-separated list)
namestringFilter by user-defined pin name
statusstringFilter by pin status (queued, pinning, pinned, failed)
limitintegerMaximum number of results to return
beforestringReturn results created before this ISO 8601 timestamp
afterstringReturn results created after this ISO 8601 timestamp

Gateway API

Overview

The Pinion Gateway provides HTTP access to content stored in the IPFS blockstore by CID. It implements the IPFS HTTP Gateway specification, including full content-type negotiation via the Accept header.

Because Pinion uses a shared blockstore, content uploaded through the Upload Service is immediately retrievable through the Gateway — even before the worker has finished processing the pin request.

Base URL

https://<environment>.pinion.build/gateway

Authentication

Two authentication methods are supported, routed at different paths:

MethodPath prefixRequired
JWT Bearer token/gateway/api/v1/Gateway Service group membership
OAuth2 session (browser)/gateway/web/Active browser session cookie

Endpoint

GET /ipfs/{cid}[/path]

Retrieve content by CID. Optionally traverse into a UnixFS directory using a path suffix.

ParameterTypeDescription
cidpath (required)IPFS Content Identifier (CIDv0 or CIDv1)
pathpath (optional)Sub-path within a UnixFS directory (e.g. /index.html)

Content-Type Negotiation

Use the Accept header to request a specific response format:

Accept headerResponse
(default)Deserialized content (file bytes, HTML for directories)
application/vnd.ipld.carCAR archive of the DAG rooted at the CID
application/vnd.ipld.rawRaw block bytes for the exact CID
application/jsonJSON representation (for IPLD JSON nodes)

Caching

Responses include standard HTTP caching headers. Because IPFS content is content-addressed and immutable, responses for a given CID are safe to cache indefinitely. Cache-Control: public, max-age=29030400, immutable is set by the gateway for resolved content.

Examples

Fetch a file by CID (JWT):

curl https://<environment>.pinion.build/gateway/api/v1/ipfs/bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi \
  -H "Authorization: Bearer YOUR_TOKEN"

Download a CAR archive of a DAG:

curl https://<environment>.pinion.build/gateway/api/v1/ipfs/bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/vnd.ipld.car" \
  -o content.car

Fetch a file within a directory CID:

curl https://<environment>.pinion.build/gateway/api/v1/ipfs/bafybeid.../index.html \
  -H "Authorization: Bearer YOUR_TOKEN"

Rate Limits & Billing

Gateway bandwidth is metered and billed according to your subscription plan. See the Pricing page for details.

Upload Service

Overview

The Upload Service accepts files and CAR archives, writes them directly into the shared IPFS blockstore, and creates a pin request for asynchronous processing by the worker cluster. Content is immediately available via the Gateway upon upload — before the pin is confirmed.

Two upload formats are supported:

  • Regular file — any file; chunked and organized into a UnixFS DAG automatically.
  • CAR archive — a pre-built IPFS DAG in Content Addressable aRchive format. Supports multiple roots; each root becomes a separate pin.

Base URL

https://<environment>.pinion.build/upload

Authentication

MethodPath prefixRequired
JWT Bearer token/upload/api/v1/Upload Service group membership
OAuth2 session (browser)/upload/web/Active browser session cookie

Endpoint

POST /

Upload a file or CAR archive to IPFS.

Query Parameters
NameTypeDescription
formatstringSet to car to treat the body as a CAR archive. Alternatively, set Content-Type: application/vnd.ipld.car.
namestringHuman-readable label for the pin. For CAR files with multiple roots, -root-0, -root-1, … are appended automatically.
Request Body
Content-TypeBody
multipart/form-dataForm field file containing the file bytes
application/octet-streamRaw file bytes in the request body
application/vnd.ipld.carCAR archive bytes in the request body

Response

Returns a PinStatus object on success, or an array of PinStatus objects when a CAR file contains multiple roots.

// Single root
{
  "requestid": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pinning",
  "created": "2025-01-15T12:00:00Z",
  "pin": {
    "cid": "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
    "name": "my-file"
  }
}

Behavior

After upload, the pin enters pinning status. A worker node picks up the request from the pubsub queue, verifies the content is present in the blockstore, and transitions the pin to pinned. Because content is written directly to the shared blockstore on upload, it is retrievable via the Gateway immediately — not only after pinning completes.

Examples

Upload a regular file (multipart):

curl -X POST https://<environment>.pinion.build/upload/api/v1/ \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -F "file=@./myfile.txt" \
  -G --data-urlencode "name=myfile"

Upload raw bytes (octet-stream):

curl -X POST https://<environment>.pinion.build/upload/api/v1/?name=myfile \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @./myfile.txt

Upload a CAR archive (via Content-Type):

curl -X POST https://<environment>.pinion.build/upload/api/v1/?name=my-dag \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/vnd.ipld.car" \
  --data-binary @./content.car

Upload a CAR archive (via query param, useful when Content-Type cannot be set):

curl -X POST "https://<environment>.pinion.build/upload/api/v1/?format=car&name=my-dag" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  --data-binary @./content.car

GitHub Integration

Overview

Pinion integrates with GitHub as a GitHub App. Once installed on your account or organization, Pinion monitors your repositories and automatically pins content to IPFS based on a configuration file you commit to each repository.

No CI pipeline changes are needed. Pinion responds directly to GitHub webhook events.

Green checkmarks on every commit

Pinion posts a commit status to GitHub under the pinion/ipfs context. When pinning succeeds, the status turns green and includes the IPFS CID. Clicking Details opens the pinned content directly in the Pinion gateway.

What Gets Pinned

  • Repository content — pin the full repository or specific subdirectories on every push to your configured branch.
  • Subdirectories — pin one or more paths within your repository (e.g. docs/, dist/) independently.
  • Release assets — pin the files attached to a GitHub release when it is published.
  • Filtered release assets — use glob patterns to pin only specific assets (e.g. *.tar.gz), and control whether auto-generated source code archives are included.

Installation

  1. Sign in to Pinion and go to your Profile page.
  2. Click Connect GitHub and install the Pinion GitHub App on your account or organization.
  3. Add a pinion.build.yaml file to the root of any repository you want Pinion to monitor.

Configuration: pinion.build.yaml

Place this file at the root of your repository. Sections you omit are ignored.

version: 1

# Release asset pinning - supports pattern matching
release_assets:
  enabled: true
  include_source_code: true
  patterns:
    - "*.txt"
    - "*.tar.gz"


# Directory monitoring - supports multiple paths and branch selection
subdirectories:
  enabled: true
  branch: "main"        # Git branch to monitor (default: "main")
  paths:
    - "docs/"           # Pin documentation directory
    - "static/"         # Pin static assets
    - "dist/"           # Pin build output
    - "data/"           # Pin data files
release_assets
FieldTypeDescription
enabledboolPin assets when a release is published
patternsstring[]Glob patterns to filter which assets are pinned. If omitted, all assets are pinned.
include_source_codeboolWhether to include the auto-generated source code archives (source.zip, source.tar.gz) that GitHub attaches to every release.
subdirectories
FieldTypeDescription
enabledboolPin the listed paths on each push
branchstringBranch to monitor. Defaults to main.
pathsstring[]Repository paths to pin. Each path is pinned independently and receives its own CID.

Monitoring

Each webhook event Pinion receives is recorded with a status and any processing messages. You can review these events from your GitHub Events page to diagnose configuration issues or confirm that pins were created successfully.

Prover API

The Prover API adds cryptographic proofs of storage to your pinned content. Rather than trusting that your data is safe, you can issue mathematical challenges to Pinion servers and verify the responses yourself — no Pinion involvement in the verification step. See the Storage Proofs page for a full explanation of the protocols.

Prover Keys

A prover key is a server-held cryptographic keypair generated for a specific proof protocol. Creating a key returns a client_setup blob — the public material you need to generate challenges and verify proofs. The signing secret stays on the server. One key can cover many pinned CIDs simultaneously.

FieldTypeDescription
key_idstring (UUID)Unique identifier for this key. Pass it to /prove and tagging endpoints.
client_setupbytes (base64)Protocol-specific public material used to construct challenges and verify proofs.
protocolstringOne of sw-priv, sw-pub, ateniese, erway, bjo.
audit_countintNumber of successful proof rounds completed with this key.
blocks_auditedintCumulative number of blocks sampled across all proof rounds.

Supported protocols:

ProtocolTypeProof SizeChallengesPublic Verify
sw-privPORO(S) field elementsUnlimitedNo
sw-pubPORO(S) group elementsUnlimitedYes
ateniesePDPO(1)UnlimitedNo
erwayPDP+UpdatesO(log n)UnlimitedYes
bjoPORO(1) per roundBounded (Q)No

Tags & Data

A tagis a small cryptographic authentication value computed from a block’s content and identity. When you call POST /tag, the service walks the full IPFS DAG of the given root CID and computes one tag per block. Tags are stored server-side. You receive the ordered list of block CIDs (block_ids) which you use to construct challenges client-side.

Multiple roots can be tagged under one key. The prover merges all tagged roots into a single proof when challenged with an empty roots array.

Lifecycle

Proof of storage for a set of pinned CIDs follows five phases. Steps 1–2 are setup (done once). Steps 3–5 repeat each audit round.

1

Create a key

Choose a protocol and challenge size. Store the returned client_setup and key_id.

POST /prover/api/v1/challenge-key
{"protocol": "sw-priv", "challenge_size": 20}
→ {"key_id": "…uuid…", "client_setup": "…base64…"}
2

Tag each pinned root

Call once per root CID. Store the returned block_ids for that root.

POST /prover/api/v1/tag
{"root": "bafybeig…", "key_id": "…uuid…"}
→ {"block_ids": ["…", "…", …]}
3

Generate a challenge (client-side)

Use the client library with client_setup and block_ids to produce opaque challenge bytes and a local validator. No network call.

4

Submit the challenge (no auth required)

Pass key_id, optionally a list of root CIDs (empty = all tagged roots), and the challenge bytes. Receive raw proof bytes.

POST /prover/prove
{"key_id": "…uuid…", "roots": [], "challenge": "…base64…"}
→ <binary proof bytes>
5

Verify the proof (client-side)

Call validator.Verify(challenge, proof) using the local validator from step 3. true = data intact. false = tampering or data loss detected. No network call.

Endpoints

Key Management — requires Bearer JWT or OAuth session
MethodPathBody / ParamsResponse
POST/prover/api/v1/challenge-key{"protocol": "sw-priv", "challenge_size": 20}{key_id, client_setup}
GET/prover/api/v1/challenge-keysArray of ChallengeKeyInfo
DELETE/prover/api/v1/challenge-key/:id204 No Content
Tagging — requires Bearer JWT or OAuth session
MethodPathDescriptionResponse
POST/prover/api/v1/tagTag a pinned root CID under a key{block_ids: [...]}
GET/prover/api/v1/setupFetch client_setup + all block_ids for a key (?key_id=){client_setup, roots:[...]}
POST/prover/api/v1/registerClient-side tag upload (Ateniese flow — caller computes tags)204 No Content
DELETE/prover/api/v1/register/:key_id/:rootRemove tags for one root CID204 No Content
Proving — no authentication required
MethodPathBodyResponse
POST/prover/prove{key_id, roots, challenge}Raw proof bytes (application/octet-stream)
curl -X POST https://<env>.pinion.build/prover/prove \
  -H "Content-Type: application/json" \
  -d '{"key_id":"<uuid>","roots":[],"challenge":"<base64>"}' \
  --output proof.bin