Skip to content

POST /api/upload

Stages a file on the Prova network.

http
POST /api/upload?cid=bafy…q4kr HTTP/1.1
Host: prova.network
Authorization: Bearer pk_live_eyJ...
Content-Type: application/octet-stream
X-Filename: my-site.tar.gz
Content-Length: 4194304

<raw bytes>

Query parameters

ParamTypeRequiredDescription
cidstringyesThe content-addressed id of the bytes you're about to send. Must match the regex ^[a-z0-9]{8,80}$/i. Compute it client-side.

Headers

HeaderRequiredDescription
AuthorizationoptionalBearer pk_live_…. If omitted, falls back to sponsored mode (anonymous, IP-rate-limited).
Content-TypeyesMime type of the bytes. Returned verbatim on retrieval.
Content-LengthyesBody size in bytes. Used for cap enforcement.
X-FilenamenoSuggested filename for retrieval (Content-Disposition). URL-encoded.

Body

Raw bytes. The Content-Type header tells the server what they are.

Response

json
{
  "cid":          "bafy…q4kr",
  "dealId":       "d-0x9c4f",
  "size":         4194304,
  "retrievalUrl": "https://prova.network/p/bafy…q4kr",
  "term":         "30 days",
  "sponsored":    false,
  "owner":        "you@example.com"
}
  • dealId — synthetic during pre-mainnet. After mainnet, it's the on-chain deal id from StorageMarketplace.sol.
  • sponsoredtrue if the upload went through without a token (anonymous tier).
  • ownernull for sponsored uploads, your email for authenticated.

Tiers

TierAuthFile sizeDaily cap
Sponsorednone100 MB200 MB / IP
Free tokenpk_live_…5 GiB1 GiB / day
Walletwallet sigunlimited*quota = USDC balance

*Bounded by gas costs and prover capacity.

Errors

StatuserrorWhen
400invalid_cidcid query param missing or malformed
400no_bodyRequest body is empty
400empty_bodyBody present but zero bytes
401invalid_tokenAuth header present but token invalid/expired
403insufficient_scopeToken lacks the put scope
413too_largeFile exceeds the tier's per-file limit
429rate_limitedSponsored daily IP cap hit
429quota_exceededAuthenticated daily user quota hit
502stage_failedUpstream prover rejected the upload
503storage_offlineNo storage backend bound (configuration error)

Examples

CLI / curl (with token)

bash
TOKEN="pk_live_..."
CID=$(prova hash ./my-site.tar.gz)   # or compute manually
curl -X POST "https://prova.network/api/upload?cid=$CID" \
  -H "authorization: Bearer $TOKEN" \
  -H "content-type: application/octet-stream" \
  -H "x-filename: my-site.tar.gz" \
  --data-binary @./my-site.tar.gz
bash
curl -X POST "https://prova.network/api/upload?cid=$CID" \
  -H "content-type: image/png" \
  -H "x-filename: screenshot.png" \
  --data-binary @./screenshot.png

From a Web app

js
const buf = await file.arrayBuffer();
const cid = await computeCid(buf);   // see /api/piece-cids docs

const res = await fetch(`/api/upload?cid=${cid}`, {
  method: 'POST',
  headers: {
    'authorization': `Bearer ${token}`,
    'content-type': file.type,
    'x-filename': encodeURIComponent(file.name),
  },
  body: file,
});
const { retrievalUrl } = await res.json();

Streaming

The endpoint accepts streaming bodies. The Content-Length must be set up front (no chunked transfer-encoding for now). For files larger than 100 MB on the authenticated tier, the SDK splits into chunks and uploads each piece independently.

Apache-2.0 OR MIT.