# tusky.ai

S3 for AI agents, minus the signup.

Stateless, no-login blob storage on Walrus, paid in USDC on Sui over x402.
An agent with a Sui keypair and a USDC balance can store data, batch files
into quilts, and renew storage — no account, no API key, no session.

> Currently running on **Sui testnet + Walrus testnet** with test USDC.

## How it works

1. `POST /v1/quote` with declared file sizes and epochs. You get back a
   signed quote and standard x402 payment requirements (HTTP 402). No bytes
   needed to price — cost is a deterministic function of size.
2. Pay the quoted USDC amount by signing an x402 payment header.
3. `POST /v1/store` with the bytes, the `quoteId`, and the `X-PAYMENT`
   header. The service stores on Walrus and mints the Sui `Blob` object
   **to your address**, gas sponsored.
4. You receive a fat receipt. Cache it — you never need us again to read.

## Endpoints

| Method | Path | What |
|---|---|---|
| POST | /v1/quote | Price files from declared sizes → signed quote + x402 requirements |
| POST | /v1/store | Bytes + quoteId + X-PAYMENT header → receipt (N files → one quilt) |
| GET | /v1/blobs/{blobId} | Read a blob (free, redirects to a public Walrus aggregator) |
| GET | /v1/quilts/{quiltId}/{identifier} | Read one file from a quilt (free, redirects) |
| POST | /v1/extend/quote | Price extending a blob/quilt (`{suiObjectId, epochs}`) → signed quote + x402 |
| POST | /v1/extend | Pay the extend quote → storage extended, updated receipt |
| GET | /v1/receipts?owner=0x… | Your holdings, reconstructed live from Sui (add `&expand=files` for quilt contents) |
| GET | /v1/health | Status, current WAL rate, epoch info |

Agent tooling: an **MCP server** (`store`, `store_batch`, `extend`, `list`,
`fetch`) and the **`@tusky/sdk`** TypeScript client live in the repo — see the
README quickstart. Both do the x402 payment dance locally; your key never
leaves your machine.

## Example

```sh
curl -s -X POST https://tusky.ai/v1/quote \
  -H 'content-type: application/json' \
  -d '{"files":[{"size":2048}],"epochs":10}'
# → 402 with { quote: { quoteId, token, priceMicroUsdc, ... },
#              paymentRequirements: { ...x402 USDC-on-Sui... } }
```

## Things you should know

- **The receipt is the database.** We keep zero rows of user data. "What did
  I store?" is a Sui query for objects owned by your address.
- **Reads are free and lock-in is zero.** A `blobId` is content-addressed
  and public — fetch it from any Walrus aggregator, bypassing us entirely.
- **Quilts extend all-or-nothing.** N files stored in one call become one
  quilt: one Sui object, one expiry. Batch accordingly.
- **Lost keypair = lost extension rights.** Reads still work until expiry
  (the blobId stays public), but only the owning address can renew.
- **We never encrypt and never hold keys.** Encrypt client-side before
  upload if you need confidentiality.
- Quotes expire in ~60s; retries are safe — store is idempotent on
  `quoteId` and on `(content hash, epochs)`. If payment settles but
  storage permanently fails, USDC is auto-refunded to the payer.

## For agents

- This page in markdown: `GET /` (any non-HTML Accept) or `GET /llms.txt`.
- Errors are structured JSON: `{code, message, retryable}` — e.g.
  `QUOTE_EXPIRED`, `SIZE_MISMATCH`, `PAYMENT_INVALID`,
  `STORE_FAILED_REFUNDED`.
- Identity is your Sui keypair; payment is USDC on Sui via x402. You never
  need SUI for gas or WAL tokens.
