# Storage Costs

Understanding storage costs helps you budget effectively and avoid service interruptions. This guide covers the SDK APIs for calculating costs, funding your account, and querying account state.

:::tip[How It Works]
For a conceptual overview of how payments work: deposits, payment rails, lockup, and what happens when funds run low, see the [Payments & Storage cookbook](/cookbooks/payments-and-storage/).
:::

Storage operates on a **pay-per-epoch** model where you deposit USDFC tokens and set allowances that control how much the storage service can spend.

:::tip[What is an Epoch?]
An **epoch** is Filecoin's block time, which is 30 seconds. Storage costs are calculated per epoch, ensuring you only pay for the storage time you actually use.
:::

## Pricing Components

| Component | Cost | Notes |
| -------------- | ------------------ | -------------------------------------------------------- |
| **Storage** | $2.50/TiB/month | Minimum $0.06/month per data set (~24.567 GiB threshold) |
| **Sybil Fee** | 0.1 USDFC (one-time) | Per new data set creation; prevents state-growth spam |
| **CDN Egress** | $14/TiB downloaded | 1 USDFC top-up ≈ 71.5 GiB of downloads |
| **CDN Setup** | 1 USDFC (one-time) | Per data set; reusing existing data sets incurs no cost |

:::note[Be aware]
Per month means **per 30 days** here, not calendar month like a traditional storage service.
:::
**Pricing Logic:**

- Storage **< 24.567 GiB**: Minimum $0.06/month applies
- Storage **≥ 24.567 GiB**: Actual cost `(bytes / TiB) × $2.50/month`
- CDN data sets require 1 USDFC setup on first creation only
- CDN egress credits can be topped up anytime

### Real-World Cost Examples

These examples use plain arithmetic for clarity. For programmatic cost calculation, use `getUploadCosts()` — see [Querying Upload Costs](#querying-upload-costs) below.

#### Example 1: NFT Collection (10,000 × 5 KiB ≈ 48.82 MiB)

```ts twoslash
// @lib: esnext,dom
// 48.82 MiB less than 24.567 GiB threshold
// Price is $0.06/month
const PRICE_PER_MONTH = 0.06;
const months = 24;
const PRICE_FOR_24_MONTHS = PRICE_PER_MONTH * 24; // 1.44 USDFC
```

| Duration  | Total Cost |
| --------- | ---------- |
| 1 month   | 0.06 USDFC |
| 24 months | 1.44 USDFC |

---

#### Example 2: User Content Platform with CDN

- **Storage:** 1,000 users × 100 MiB ≈ 100,000 MiB
- **Traffic:** 1,000 users × 100 MiB/month ≈ 100,000 MiB/month egress

```ts twoslash
// @lib: esnext,dom
const STORAGE_PRICE_PER_TIB_PER_MONTH = 2.5; // $2.50/TiB/month
const CDN_EGRESS_PRICE_PER_TIB = 14; // $14/TiB downloaded
const storageMiB = 100_000;
const egressMiB = 100_000;

// Storage: 100,000 MiB ≈ 0.0953 TiB
const storageTiB = storageMiB / 1024 / 1024;

// Egress: 100,000 MiB ≈ 0.0953 TiB
const egressTiB = egressMiB / 1024 / 1024;

// Storage cost per month: 0.0953 TiB × $2.50 ≈ $0.238/month
const storageCostPerMonth = storageTiB * STORAGE_PRICE_PER_TIB_PER_MONTH;

// Egress cost per month: 0.0953 TiB × $14 ≈ $1.334/month
const egressCostPerMonth = egressTiB * CDN_EGRESS_PRICE_PER_TIB;

// Total cost per month: $0.238/month + $1.334/month ≈ $1.572/month
const totalCostPerMonth = storageCostPerMonth + egressCostPerMonth;

// Total cost for 24 months: $1.572/month × 24 ≈ $37.728
const totalCostFor24Months = totalCostPerMonth * 24;
```

| Cost Component | Per Month | 24 Months |
| -------------- | ---------------- | ----------------- |
| Storage | ≈ 0.238 USDFC | ≈ 5.71 USDFC |
| CDN Egress | ≈ 1.334 USDFC | ≈ 32.016 USDFC |
| **Total** | **≈ 1.572 USDFC** | **≈ 37.728 USDFC** |

## Querying Upload Costs

Use `getUploadCosts()` to preview costs without executing any transaction. This is useful for displaying pricing in a UI or letting users confirm before proceeding.

Getting the costs for uploading to an existing dataset:

```ts twoslash
// @lib: esnext,dom
// @noErrors
import { Synapse, SIZE_CONSTANTS } from "@filoz/synapse-sdk"
import { privateKeyToAccount } from 'viem/accounts'
const synapse = Synapse.create({ account: privateKeyToAccount('0x...'), source: 'my-app' })
// ---cut---
// With currentDataSetSize — accurate floor-aware delta
const { rate, depositNeeded } = await synapse.storage.getUploadCosts({
  isNewDataSet: false,
  currentDataSetSize: 50n * SIZE_CONSTANTS.MiB,
  dataSize: 100n * SIZE_CONSTANTS.MiB,
})
// Shows incremental cost (newRate - currentRate), handles floor-to-floor

// Without currentDataSetSize — safe overestimate for floor cases
const costs2 = await synapse.storage.getUploadCosts({
  isNewDataSet: false,
  dataSize: 100n * SIZE_CONSTANTS.MiB,
})
// Accurate for above-floor datasets, overestimates for floor-priced ones
```

Getting the costs for uploading to a new dataset:

```ts twoslash
// @lib: esnext,dom
// @noErrors
import { Synapse, formatUnits, SIZE_CONSTANTS } from "@filoz/synapse-sdk"
import { privateKeyToAccount } from 'viem/accounts'
const synapse = Synapse.create({ account: privateKeyToAccount('0x...'), source: 'my-app' })
// ---cut---
const { rate, depositNeeded, needsFwssMaxApproval, ready } = await synapse.storage.getUploadCosts({
  dataSize: 100n * SIZE_CONSTANTS.MiB,
  isNewDataSet: true,
  withCDN: true,
})

// Storage rate per epoch (30 seconds)
console.log("Rate per epoch:", formatUnits(rate.perEpoch), "USDFC")
// Storage rate per month
console.log("Rate per month:", formatUnits(rate.perMonth), "USDFC")
// USDFC to deposit
console.log("Deposit needed:", formatUnits(depositNeeded), "USDFC")
// Whether FWSS needs to be approved
console.log("Needs approval:", needsFwssMaxApproval)
// Whether the account is ready to upload
console.log("Ready to upload:", ready)
```

## Upload Preparation

Before uploading, the **WarmStorage operator** must be approved and your account must be funded. FWSS uses a 30-day lockup (prepayment) period. If your account becomes underfunded, the provider may terminate the storage agreement, after which you have 30 days before data removal.

:::tip[Typical Flow]
**Query costs** → **prepare transaction** → **execute** → **upload**. The `prepare()` method handles the middle steps in one call.
:::

`prepare()` computes costs and returns a ready-to-execute transaction. This is the recommended approach — it handles deposit calculation, operator approval, and contract call routing in one step.

```ts twoslash
// @lib: esnext,dom
import { Synapse, formatUnits, SIZE_CONSTANTS } from "@filoz/synapse-sdk";
import { privateKeyToAccount } from 'viem/accounts'
const synapse = Synapse.create({ account: privateKeyToAccount('0x...'), source: 'my-app' });
// ---cut---
const { costs, transaction } = await synapse.storage.prepare({
  dataSize: SIZE_CONSTANTS.GiB,
})

// Inspect costs
const { rate, depositNeeded } = costs // Upload costs breakdown
console.log("Rate per month:", formatUnits(rate.perMonth))
console.log("Deposit needed:", formatUnits(depositNeeded))

// Execute if the account isn't ready
if (transaction) {
  const { depositAmount, includesApproval } = transaction
  console.log("Deposit amount:", formatUnits(depositAmount))
  console.log("Includes approval:", includesApproval)

  const { hash } = await transaction.execute()
  console.log("Transaction confirmed:", hash)
}

// Now safe to upload
```

When storing data across multiple providers, pass an array of contexts. The SDK aggregates per-context lockup while computing account-level values (debt, runway, buffer) once.

```ts twoslash
// @lib: esnext,dom
import { Synapse, formatUnits, SIZE_CONSTANTS, TIME_CONSTANTS } from "@filoz/synapse-sdk"
import { privateKeyToAccount } from 'viem/accounts'
const synapse = Synapse.create({ account: privateKeyToAccount('0x...'), source: 'my-app' })

const contexts = await synapse.storage.createContexts({ copies: 3 })

// 1-year runway
const oneYear = TIME_CONSTANTS.EPOCHS_PER_MONTH * 12n

// Prepare a single deposit covering all 3 copies for 1 year
const { costs, transaction } = await synapse.storage.prepare({
  context: contexts,
  dataSize: 50n * SIZE_CONSTANTS.GiB,
  extraRunwayEpochs: oneYear,
})

const { rate, depositNeeded, ready } = costs
console.log("Monthly rate (per copy):", formatUnits(rate.perMonth), "USDFC")
console.log("Total deposit needed:", formatUnits(depositNeeded), "USDFC")
console.log("Account ready:", ready)

if (transaction) {
  const { hash } = await transaction.execute()
  console.log("Funded:", hash)
}
```

`prepare()` returns:

- **`costs`**: The full `UploadCosts` breakdown
- **`transaction`**: A transaction object with `execute()`, or `null` if the account is already ready

The transaction automatically picks the right contract call:

- **Needs deposit + approval**: calls `depositWithPermitAndApproveOperator`
- **Needs approval only**: calls `approveService`
- **Needs deposit only**: calls `depositWithPermit`
- **Already ready**: returns `transaction: null`

## Account Queries

Read-only APIs for account-level cost visibility.

```ts twoslash
// @noErrors
// Aggregate rate across all active rails
const { ratePerEpoch, ratePerMonth } = await synapse.payments.totalAccountRate()

// Sum of lockupFixed across all rails (including terminated but not finalized)
const { totalFixedLockup } = await synapse.payments.totalAccountLockup()

// Total storage size across all live datasets
import { getAccountTotalStorageSize } from '@filoz/synapse-core/warm-storage'
const { totalSizeBytes, datasetCount } = await getAccountTotalStorageSize(client, {
  address: '0x...',
})
```

All rate values come in both per-epoch (contract-native) and per-month (`ratePerEpoch * EPOCHS_PER_MONTH`) units. Note that `ratePerMonth` from `totalAccountRate()` is computed as `ratePerEpoch * EPOCHS_PER_MONTH` — this is slightly less than the full-precision `rate.perMonth` returned by `getUploadCosts()` due to integer truncation. See [Rate Precision](/cookbooks/payments-and-storage/#rate-precision) for details.

:::tip[API Reference]
For the full API — including pure calculation functions and lower-level utilities — see the [synapse-core pay reference](/reference/filoz/synapse-core/pay/toc/) and [synapse-core warm-storage reference](/reference/filoz/synapse-core/warm-storage/toc/).
:::

## Next Steps

- [Payments & Storage](/cookbooks/payments-and-storage/) — Deep dive into the payment model mechanics
- [StorageManager API Reference](/reference/filoz/synapse-sdk/storage/classes/storagemanager/) — Full SDK storage API
- [PaymentsService API Reference](/reference/filoz/synapse-sdk/payments/classes/paymentsservice/) — Full SDK payments API
- [Upload Pipeline](/developer-guides/storage/upload-pipeline/) — Upload workflows from simple to advanced
- [Storage Operations](/developer-guides/storage/storage-operations/) — Contexts, data sets, and retrieval