# Storage

OpenAPI spec: [https://api.payweave.app/app/app_wd5l3hktdnklz8d18i89r48b/openapi.json](https://api.payweave.app/app/app_wd5l3hktdnklz8d18i89r48b/openapi.json)

## Networks

| Name | Mode | CAIP-2 | Chain ID / Cluster | Protocols |
|---|---|---|---|---|
| Tempo Mainnet | live | `eip155:4217` | 4217 | mpp |
| Solana Mainnet | live | `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` | mainnet-beta | mpp, x402 |
| Base | live | `eip155:8453` | 8453 | x402 |

## Accepted Currencies

| Symbol | Name | Decimals | Network | Address | Protocols |
|---|---|---|---|---|---|
| USDC.e | Bridged USDC (Stargate) | 6 | `eip155:4217` | `0x20c000000000000000000000b9537d11c60e8b50` | mpp |
| USDC | USD Coin (Solana) | 6 | `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` | mpp, x402 |
| USDC | USD Coin | 6 | `eip155:8453` | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | x402 |

## Endpoints (2)

### Storage: List Uploads

List your wallet's uploaded objects (url, key, bytes, content_type, ttl_days, uploaded_at, expires_at). Optional ?ttl_days=1|7|30|90|365 pages one tier via ?cursor=.

- Method: GET
- Path: `/list`
- Price: $0.00100000

**Input Schema**

```json
{
  "anyOf": [
    {
      "not": {}
    },
    {
      "type": "object",
      "properties": {
        "ttl_days": {
          "type": "number",
          "enum": [
            1,
            7,
            30,
            90,
            365
          ]
        },
        "cursor": {
          "type": "string"
        }
      },
      "additionalProperties": false
    }
  ]
}
```

**Output Schema**

```json
{
  "type": "object",
  "properties": {
    "items": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "key": {
            "type": "string"
          },
          "bytes": {
            "type": "integer",
            "minimum": 0
          },
          "content_type": {
            "type": "string"
          },
          "ttl_days": {
            "type": "integer"
          },
          "uploaded_at": {
            "type": "string"
          },
          "expires_at": {
            "type": "string"
          }
        },
        "required": [
          "url",
          "key",
          "bytes",
          "content_type",
          "ttl_days",
          "uploaded_at",
          "expires_at"
        ],
        "additionalProperties": false
      }
    },
    "count": {
      "type": "integer",
      "minimum": 0
    },
    "truncated": {
      "type": "boolean"
    },
    "cursor": {
      "type": [
        "string",
        "null"
      ]
    }
  },
  "required": [
    "items",
    "count",
    "truncated",
    "cursor"
  ],
  "additionalProperties": false
}
```

## How to invoke

Payment is handled automatically — the client signs the 402 challenge and retries.

### TypeScript — Tempo (mppx + fetch) ([docs](https://mpp.dev/sdk/typescript/client))

```ts
import { privateKeyToAccount } from 'viem/accounts'
import { Mppx, tempo } from 'mppx/client'

Mppx.create({
  methods: [tempo({ account: privateKeyToAccount('0x...') })],
})

const res = await fetch('https://storage.payweave.services/list', {
  method: 'GET',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "ttl_days": 1,
    "cursor": ""
  }),
})
const data = await res.json()
```

### TypeScript — Solana (@solana/mpp + fetch) ([docs](https://github.com/solana-foundation/mpp-sdk))

```ts
import { createKeyPairSignerFromBytes } from '@solana/kit'
import { Mppx } from 'mppx/client'
import { solana } from '@solana/mpp/client'

const signer = await createKeyPairSignerFromBytes(/* 64-byte secret key */)
Mppx.create({ methods: [solana({ signer })] })

const res = await fetch('https://storage.payweave.services/list', {
  method: 'GET',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "ttl_days": 1,
    "cursor": ""
  }),
})
const data = await res.json()
```

### mppx CLI ([docs](https://mpp.dev/sdk/typescript/cli))

```sh
npx mppx "https://storage.payweave.services/list" -H 'Content-Type: application/json' -d '{"ttl_days":1,"cursor":""}'
```

### Tempo Wallet ([docs](https://docs.tempo.xyz/cli/wallet))

```sh
tempo request "https://storage.payweave.services/list" --json '{"ttl_days":1,"cursor":""}'
```

### pay.sh — Solana Foundation ([docs](https://pay.sh))

```sh
pay --mainnet curl "https://storage.payweave.services/list" -H 'Content-Type: application/json' -d '{"ttl_days":1,"cursor":""}'
```

### agentcash CLI ([docs](https://www.npmjs.com/package/agentcash))

```sh
npx agentcash fetch "https://storage.payweave.services/list" -m GET -b '{"ttl_days":1,"cursor":""}' -p mpp
```

### x402 — Base / Solana USDC (x402-fetch) ([docs](https://x402.org))

```ts
import { wrapFetchWithPayment } from 'x402-fetch'
import { privateKeyToAccount } from 'viem/accounts'

const account = privateKeyToAccount('0x...') // Base USDC wallet
const fetchWithPay = wrapFetchWithPayment(fetch, account)

const res = await fetchWithPay('https://storage.payweave.services/list', {
  method: 'GET',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "ttl_days": 1,
    "cursor": ""
  }),
})
const data = await res.json()
```

### x402 — agentcash CLI

```sh
npx agentcash fetch "https://storage.payweave.services/list" -m GET -b '{"ttl_days":1,"cursor":""}' -p x402
```

### Storage: Upload

Upload a local file via multipart/form-data and receive a permanent public URL. TTL tier (1 / 7 / 30 / 90 / 365 days, default 30) drives both price ($0.001–$0.01 USDC) and storage lifetime. Body is validated pre-charge — invalid bodies return 400 without settling. Files are publicly accessible to anyone holding the returned URL — URLs are unguessable but not secret. Do not upload secrets, credentials, PII, or private business data.

- Method: POST
- Path: `/upload`
- Price: $0.00100000
- Content-Type: multipart/form-data

**Input Schema**

```json
{
  "type": "object",
  "properties": {
    "file": {},
    "ttl_days": {
      "type": "number",
      "enum": [
        1,
        7,
        30,
        90,
        365
      ]
    }
  },
  "required": [
    "file"
  ],
  "additionalProperties": false
}
```

**Output Schema**

```json
{
  "type": "object",
  "properties": {
    "url": {
      "type": "string",
      "format": "uri",
      "description": "Public-read URL for the uploaded object. Lives until expires_at."
    },
    "key": {
      "type": "string",
      "description": "R2 object key. Same wallet-hash prefix as everything you upload."
    },
    "bytes": {
      "type": "integer",
      "minimum": 0,
      "description": "Stored byte count."
    },
    "content_type": {
      "type": "string",
      "description": "Content-Type stored on the R2 object and served on read."
    },
    "ttl_days": {
      "type": "integer",
      "description": "TTL tier the object was filed under: 1, 7, 30, 90, or 365."
    },
    "expires_at": {
      "type": "string",
      "description": "ISO-8601 timestamp at which R2 lifecycle will delete the object."
    }
  },
  "required": [
    "url",
    "key",
    "bytes",
    "content_type",
    "ttl_days",
    "expires_at"
  ],
  "additionalProperties": false
}
```

## How to invoke

Payment is handled automatically — the client signs the 402 challenge and retries.

### TypeScript — Tempo (mppx + fetch) ([docs](https://mpp.dev/sdk/typescript/client))

```ts
import { privateKeyToAccount } from 'viem/accounts'
import { Mppx, tempo } from 'mppx/client'

Mppx.create({
  methods: [tempo({ account: privateKeyToAccount('0x...') })],
})

const form = new FormData()
form.append('file', /* File from <input> or Blob */, 'file.bin')
form.append('ttl_days', '1')

const res = await fetch('https://storage.payweave.services/upload', {
  method: 'POST',
  body: form,
})
const data = await res.json()
```

### TypeScript — Solana (@solana/mpp + fetch) ([docs](https://github.com/solana-foundation/mpp-sdk))

```ts
import { createKeyPairSignerFromBytes } from '@solana/kit'
import { Mppx } from 'mppx/client'
import { solana } from '@solana/mpp/client'

const signer = await createKeyPairSignerFromBytes(/* 64-byte secret key */)
Mppx.create({ methods: [solana({ signer })] })

const form = new FormData()
form.append('file', /* File from <input> or Blob */, 'file.bin')
form.append('ttl_days', '1')

const res = await fetch('https://storage.payweave.services/upload', {
  method: 'POST',
  body: form,
})
const data = await res.json()
```

### mppx CLI ([docs](https://mpp.dev/sdk/typescript/cli))

```sh
npx mppx "https://storage.payweave.services/upload" -X POST -F "file=@./file.bin" -F "ttl_days=1"
```

### Tempo Wallet ([docs](https://docs.tempo.xyz/cli/wallet))

```sh
tempo request "https://storage.payweave.services/upload" -X POST -F "file=@./file.bin" -F "ttl_days=1"
```

### pay.sh — Solana Foundation ([docs](https://pay.sh))

```sh
pay --mainnet curl "https://storage.payweave.services/upload" -X POST -F "file=@./file.bin" -F "ttl_days=1"
```

### x402 — Base / Solana USDC (x402-fetch) ([docs](https://x402.org))

```ts
import { wrapFetchWithPayment } from 'x402-fetch'
import { privateKeyToAccount } from 'viem/accounts'

const account = privateKeyToAccount('0x...') // Base USDC wallet
const fetchWithPay = wrapFetchWithPayment(fetch, account)

const form = new FormData()
form.append('file', /* File from <input> or Blob */, 'file.bin')
form.append('ttl_days', '1')

const res = await fetchWithPay('https://storage.payweave.services/upload', {
  method: 'POST',
  body: form,
})
const data = await res.json()
```
