Storage docs
MeterCall's storage layer is decentralized by default. IPFS for hot content, Arweave for permanence, Filecoin for cold long-tail. One API, three tiers, five public gateways with automatic fallback.
Overview
Every module page, every bridge attestation, every receipt can be pinned to decentralized storage. In dev mode the server returns deterministic fake CIDs so you can wire up your UI without real keys. When you set WEB3_STORAGE_TOKEN, PINATA_JWT, or BUNDLR_KEY, the same endpoints start issuing real CIDs.
Retrieval is always live: the /v1/storage/resolve/:cid endpoint races 5 public gateways in parallel and returns the fastest responder plus the full fallback list.
Tiers
| Tier | Price | Persistence | Best for |
|---|---|---|---|
| ipfs | ~$0.0001/MB/mo | 180 days typical | Modules, HTML, hot pages |
| arweave | ~$2/GB one-time | Forever (200y horizon) | Bridge attestations, receipts |
| filecoin | ~$0.003/GB/mo | Years (provable deals) | Long-tail catalog, analytics |
Endpoints
| Method & path | Purpose |
|---|---|
| POST /v1/storage/pin | Pin arbitrary content |
| POST /v1/storage/pin-url | Fetch URL, then pin |
| GET /v1/storage/resolve/:cid | Gateway race & fallback |
| GET /v1/storage/gateway/status | Live gateway health, 60s cache |
| POST /v1/storage/pin-module/:slug | Pin a module's built HTML |
| POST /v1/storage/arweave/attest | Queue attestation for Arweave |
| GET /v1/storage/stats | Aggregate metrics |
| POST /v1/storage/mirror-catalog | Pin all modules (batched) |
| GET /v1/storage/mirror/:jobId | Mirror job progress |
Pin content
# POST /v1/storage/pin curl -sX POST https://metercall.ai/v1/storage/pin \ -H "Content-Type: application/json" \ -d '{"content":"hello, decentralized world","tier":"ipfs"}' # → { cid, gateway_urls, pin_id, size_bytes, estimated_persistence_days, cost }
Pin a URL
curl -sX POST https://metercall.ai/v1/storage/pin-url \ -H "Content-Type: application/json" \ -d '{"url":"https://metercall.ai/l4.html","tier":"ipfs"}'
Resolve a CID
curl -s https://metercall.ai/v1/storage/resolve/bafkreiabc123… # → races 5 public gateways, returns fastest + full fallback list
Mirror the whole catalog
curl -sX POST https://metercall.ai/v1/storage/mirror-catalog # → { job_id, total, poll: "/v1/storage/mirror/{id}" } curl -s https://metercall.ai/v1/storage/mirror/mir_… # → { done, total, failed, progress_pct, status }
Archive an attestation on Arweave
curl -sX POST https://metercall.ai/v1/storage/arweave/attest \ -H "Content-Type: application/json" \ -d '{"attestation_payload":{"bridge":"usdc-base-to-sol","tx":"0xabc","amount":"100"}}' # → { queued: true, arweave_tx_id, viewer_url: "https://arweave.net/{id}" }
CID format
Real CIDs are multibase-encoded multihashes. MeterCall uses CIDv1 with base32 lowercase (prefix bafkrei…) so links work with every major public gateway. In stub mode we synthesize a deterministic lookalike by base32-encoding a SHA-256 of the input. Same content → same CID, every time.
Gateway fallback
Every pin response includes gateway_urls — five public gateways in preferred order. Always try the first; if you get a 404 or >3s timeout, rotate to the next. /v1/storage/resolve/:cid does this race for you.
ipfs.io/ipfs/{cid}dweb.link/ipfs/{cid}cloudflare-ipfs.com/ipfs/{cid}gateway.pinata.cloud/ipfs/{cid}4everland.io/ipfs/{cid}
BYO keys
To flip from stub to live, set one or more of these env vars before boot:
| Env var | Source | Purpose |
|---|---|---|
| WEB3_STORAGE_TOKEN | web3.storage (free 5GB) | IPFS + Filecoin cold backup |
| PINATA_JWT | Pinata (free 1GB) | IPFS pinning |
| BUNDLR_KEY | Bundlr / Turbo | Arweave uploads |
No keys required for reads — public gateways are always free.
Pinning patterns
Pattern 1 — module-first
When a module is built, immediately POST /v1/storage/pin-module/:slug. The returned CID is recorded in global._moduleCids so subsequent page loads can prefer the IPFS gateway.
Pattern 2 — attestation-first
When the bridge emits a new attestation, pipe it through /v1/storage/arweave/attest. Permanence is guaranteed by the one-time fee.
Pattern 3 — cold tail
Nightly job: anything older than 90 days and rarely accessed → re-pin with tier:"filecoin" and drop the IPFS pin.
Arweave permanence guarantees
Arweave's storage endowment model charges a one-time fee sized to cover storage for 200+ years at declining hardware costs. Each attestation we archive gets a 43-character base64url tx id viewable at https://arweave.net/{id}.
Filecoin cold paths
We cold-store via web3.storage's Filecoin backups; retrieval uses the w3s.link gateway. For programmatic deals, set WEB3_STORAGE_TOKEN.
Billing
Each storage call is metered the same way as any other MeterCall API call — a small per-call toll. Actual pin costs passthrough from the underlying provider. See the cost calculator.
Migration from centralized storage
- Deploy with all three env vars unset — stubs everywhere, nothing breaks.
- Get a free Pinata JWT; set
PINATA_JWT. Stubs become real CIDs for new pins; old CIDs still resolve from the deterministic stub map. - Run
POST /v1/storage/mirror-catalogonce. All 2,866 modules pinned. - Add
BUNDLR_KEYwhen you're ready to archive bridge attestations.
No client code changes required at any step — every endpoint returns the same shape.