One endpoint. One payment. No accounts. No recurring billing. Files expire automatically — down to the second.
Think of it like a parking meter. You pay for a spot, for a defined time, then it expires automatically. Wallet = identity. No signup required. Store it. Pay for it. Done.
Discover and quote are optional. If you already know the rate and wallet address, skip straight to the upload — one POST and you're done.
POST to /api/store with an x402 payment header, your file as the body, and three headers: X-File-Name, X-Size-Bytes, X-Duration-Seconds. Receipt comes back in the response.
Hit /api/pricing once to get the rate and wallet address. Cache it — it rarely changes.
Call /api/quote to confirm exact price. Or calculate yourself: (bytes/1GB) × (seconds/86400) × $0.001.
One POST with x402 payment header and file body. Everything happens in a single atomic request.
Write the lease_id and expires_at. File physically deletes itself when the lease expires — to the second.
No SDK. No IAM. No billing account. Just HTTP.
// ── OPTIONAL: discover pricing once and cache it ───────────────────────── const pricing = await fetch('https://stashdata.dev/api/pricing').then(r => r.json()); // → { rateUsdcPerGbDay: 0.001, walletAddress: '0x...', minDurationSeconds: 60 } // ── OPTIONAL: get an exact quote ───────────────────────────────────────── const quote = await fetch( `https://stashdata.dev/api/quote?size_bytes=${fileBytes}&duration_seconds=3600` ).then(r => r.json()); // → { priceUsdc: 0.01, expiresAt: '2026-04-16T17:00:00Z' } // ── REQUIRED: pay and upload in one request ─────────────────────────────── const receipt = await fetch('https://stashdata.dev/api/store', { method: 'POST', headers: { 'X-Payment': buildX402Header(quote.priceUsdc, pricing.walletAddress), 'X-File-Name': 'report.pdf', 'X-Size-Bytes': String(fileBytes), 'X-Duration-Seconds': '3600', // 1 hour — be precise, don't over-specify 'Content-Type': 'application/pdf', }, body: fileStream, }); // → { lease_id, object_key, expires_at, duration_human: '1 hour', paid_usdc }
You're not cheaper than S3. You're categorically different from S3.
Once you've stored a file, you can issue a sealed handoff token — a one-time (or N-time) claim URL you pass to another agent. No auth required to claim. The token IS the credential.
Think of it as a self-destructing sealed envelope. Agent A stores a file and seals it. Agent B receives the claim URL and opens it. The envelope is gone. No shared backend, no trust required between agents.
Upload file, get lease_id back in receipt.
POST to /api/handoff/{lease_id} with max_claims and optional delete_on_claim. Get back a claim_url.
Pass the claim_url to Agent B through any channel — message queue, shared context, webhook.
GET the claim_url — no auth, no wallet, no setup. File streams back. If delete_on_claim, it's physically deleted immediately after.
// Agent A — after uploading, issue a handoff token const handoff = await fetch(`https://stashdata.dev/api/handoff/${lease_id}`, { method: 'POST', headers: { 'Authorization': `Bearer ${jwt}` }, body: JSON.stringify({ max_claims: 1, // single use delete_on_claim: true, // physically deleted after Agent B claims it ttl_seconds: 3600, // token expires in 1 hour regardless }), }).then(r => r.json()); // → { claim_url: 'https://stashdata.dev/api/claim/abc123...', expires_at } // Pass claim_url to Agent B through any channel await messageQueue.send({ claim_url: handoff.claim_url }); // Agent B — claim the file, no auth required const file = await fetch(handoff.claim_url); // → file stream. Token is now exhausted. File deleted if delete_on_claim was true.
max_claims — how many times the token can be used (default 1) ·
delete_on_claim — physically delete from S3 after final claim (default false — owner keeps access) ·
ttl_seconds — token expiry independent of lease expiry (default 3600)
Rate: $0.001 / GB / day. Duration in seconds — specify exactly how long you need it. Many small transactions hit the network minimum, shown in green.
Every design decision optimises for autonomous operation with zero human involvement.
Agents find Stashdata via /.well-known/x402.json or /api/pricing. No documentation required.
No signup, no API key, no OAuth. The payment itself proves identity. Your wallet is your account.
Duration is specified in seconds. Files are physically deleted the moment the lease expires — not day-granularity, not best-effort.
Issue a sealed claim token from any lease. Another agent claims the file with no auth — the token IS the credential. Single-use or N-use, with optional delete-on-claim.
Files stream directly to S3 via multipart upload. 1KB or 4GB — same endpoint, flat memory.
Built on AWS S3. 99.999999999% durability. No blockchain storage, no probabilistic guarantees.
All endpoints return JSON. The store endpoint accepts a raw file body stream.
X-Payment, X-File-Name, X-Size-Bytes, X-Duration-Seconds (min 60). Returns lease_id, object_key, expires_at, duration_human.max_claims (default 1), delete_on_claim (default false), ttl_seconds (default 3600). Returns claim_url, handoff_token, expires_at./.well-known/x402.json.(bytes/1073741824) × (seconds/86400) × 0.001./api/auth/challenge + /api/auth/verify. Or use the dashboard at /dashboard.html.