# Payments & Storage

:::tip[What You'll Learn]

- The mental model: deposit USDFC, FWSS handles payments to storage providers
- How much storage costs (pricing, fees, CDN)
- What payment rails are and why each data set has up to three
- What happens if your account runs low on funds

:::

## How It Works

Storage on Filecoin Onchain Cloud uses two connected on-chain systems:

- **Filecoin Pay**: a generic payment protocol for streaming and one-time payments
- **Filecoin Warm Storage Service (FWSS)**: a storage service that builds on Filecoin Pay

Think of your Filecoin Pay account as a checking account with a running tab. You deposit USDFC, and FWSS continuously streams payments from it to storage providers on your behalf. The developer flow is:

1. **Deposit** USDFC into your Filecoin Pay account
2. **Approve** FWSS as your operator (one-time)
3. **Upload** data through the SDK
4. **FWSS handles the rest**: creating payment channels, streaming funds to storage providers

The SDK's `prepare()` method handles steps 1-2 automatically. See [Storage Costs](/developer-guides/storage/storage-costs/) for code examples.

:::tip[SDK Usage]
This cookbook explains the underlying payment model. For practical code:

- **Cost calculation & funding**: [Storage Costs](/developer-guides/storage/storage-costs/)
- **Upload workflows**: [Upload Pipeline](/developer-guides/storage/upload-pipeline/)
- **API reference**: [StorageManager](/reference/filoz/synapse-sdk/storage/classes/storagemanager/) · [PaymentsService](/reference/filoz/synapse-sdk/payments/classes/paymentsservice/)

:::

## Pricing

Two recurring rates apply per data set:

| Component | Cost | Notes |
| -------------- | -------------------- | ------------------------------------------------------- |
| **Storage** | $2.50/TiB/month per copy | Charged only while pieces exist. Empty data sets are free |
| **Proving Service** | $0.024/data set/month | Flat per-data-set fee, added on top of the storage rate |
| **CDN egress** | up to $0.014/GiB downloaded | Optional, via Filecoin Beam. About half this when served from cache |

:::note
"Month" always means exactly **30 days = 86,400 epochs** throughout the system. Filecoin epochs are ~30 seconds each.
:::

Each on-chain operation also pays a small one-time fee to the storage provider, covering the gas it spends on your behalf:

| Operation | Fee |
| -------------- | -------------------- |
| **Create data set** | $0.025 |
| **Add pieces** | $0.0005 + $0.0003 per piece |
| **Schedule piece removals** | $0.002 per call |
| **Terminate service** | $0.00112 (user-initiated only) |

These are fractions of a cent. They are drawn from a ~$0.10 lockup reserve held while the data set is active, not billed separately on each call. See [Storage Costs: How the fees and lockup work](/developer-guides/storage/storage-costs/#how-the-fees-and-lockup-work) for the mechanics.

:::caution[SDK pricing update in progress]
The per-operation fees and the additive proving fee are live in the Warm Storage contract, but the SDK cost APIs (`getUploadCosts()`, `prepare()`) are still being updated to surface them, tracked in [synapse-sdk#763](https://github.com/FilOzone/synapse-sdk/issues/763). Until that lands, returned `rate` and `depositNeeded` values reflect the previous model.
:::

### Proving Fee

The monthly cost of an active data set is `(bytes / TiB) × $2.50 + $0.024`. There is no minimum floor: a data set with no pieces costs nothing, and the rate activates when the first piece is added. Earlier pricing used a single $0.06/month minimum. The flat proving fee replaces it as an additive per-data-set charge.

### Data Set Creation Costs

Creating a data set locks a small lifecycle reserve. The storage rate starts at zero and is set automatically when you add data:

| Scenario | Minimum Funds Required |
| -------- | ---------------------- |
| No CDN | ~0.10 USDFC (lifecycle reserve lockup) |
| With CDN | ~1.10 USDFC (0.10 reserve + 0.70 CDN egress + 0.30 cache-miss) |

One-time fees such as the $0.025 creation fee are drawn from the lifecycle reserve, not added on top of these amounts.

## Payment Rails

For each data set, FWSS creates payment channels called **rails** that stream funds from your account to the storage provider. A data set can have up to three rails:

| Rail | Type | Purpose |
| -------------- | --------- | ---------------------------------------- |
| **PDP rail** | Streaming | Pays for storage at a rate per epoch |
| **CDN rail** | Fixed | 0.7 USDFC lockup for CDN egress credits |
| **Cache miss** | Fixed | 0.3 USDFC lockup for cache miss credits |

Every data set gets a PDP rail, which also holds the ~$0.10 lifecycle reserve that one-time fees draw from. CDN and cache miss rails are added only when CDN is enabled.

FWSS enforces a **30-day lockup period**: your account must always have enough funds to cover at least 30 days of storage at the current rate. Think of it as a security deposit. The funds aren't spent upfront, but they're reserved so providers are guaranteed payment even if you stop topping up.

When you add data to an existing data set, FWSS automatically adjusts the rail's payment rate. The SDK calculates the correct deposit amount for you via `getUploadCosts()` and `prepare()`.

## Operator Approval

Before FWSS can manage payment rails on your behalf, you need to approve it as an **operator** on your Filecoin Pay account. Think of this like approving a token allowance: you're authorizing FWSS to create and modify payment channels using your deposited funds.

The SDK handles this automatically: the first time you call `prepare()`, the returned transaction includes the approval alongside any needed deposit. After that, only deposits are needed.

If you're building custom integrations outside the SDK, FWSS approval uses the Filecoin Pay operator system with three allowance dimensions (rate, lockup amount, and lockup period). See the [Filecoin Pay spec](https://github.com/FilOzone/filecoin-pay/blob/main/SPEC.md) for details.

## Running Low on Funds

Your account has a **runway**: how many epochs until your account enters deficit and the standard payment flow to providers halts. The SDK exposes this as `runwayInEpochs` alongside `grossCoverageInEpochs` (the full horizon your deposit covers at the current rate, including the lockup reserve). See [Storage Costs: Account Queries](/developer-guides/storage/storage-costs/#account-queries) and [Payment Operations: Account Health Monitoring](/developer-guides/payments/payment-operations/#account-health-monitoring) for examples.

When your runway hits zero, the account is **in deficit** and several things change:

- **Uploads fail**: new storage operations require the account to be current on payments
- **Existing rails are at risk**: providers can terminate rails and claim against the lockup for up to one lockup period of payment. Termination is one-way; once a rail has an `endEpoch`, topping up your account won't bring it back. Pieces remain at the provider until they're garbage-collected, so a fresh rail can re-reference them.
- **Deposits must cover the shortfall first**: depositing into a deficit account first settles outstanding obligations before funding new storage

The SDK handles the deposit math automatically: `getUploadCosts()` and `prepare()` include any outstanding debt in the deposit amount, so a fresh upload can proceed.

**To avoid interruptions**, keep your account funded with headroom beyond the lockup reserve. Use `extraRunwayEpochs` when preparing uploads to add additional buffer.

## Advanced Details

:::note
Most developers won't need this section. The SDK abstracts these mechanics: `prepare()` and `getUploadCosts()` handle deposit calculation, debt recovery, and timing safety automatically.
:::

### Rate Precision

Storage prices are stored per-month on-chain but rails operate per-epoch. Integer division during conversion means `perEpoch × EPOCHS_PER_MONTH` is slightly less than the true monthly rate due to truncation. The SDK returns both values: use `rate.perMonth` for display and `rate.perEpoch` for on-chain math.

### Deposit Components

The deposit amount for an upload is built from four parts:

| Component | What it covers |
| ------------------- | ---------------------------------------------------------- |
| **Additional lockup** | Rate increase × 30-day lockup period, plus any CDN lockup |
| **Runway** | Extra funded time beyond the lockup (if requested) |
| **Debt** | Outstanding obligations on underfunded accounts |
| **Buffer** | Safety margin for time between balance check and transaction execution |

The buffer accounts for the fact that funds drain between when you check your balance and when the transaction lands on-chain. The SDK adds a small buffer (default: 5 epochs ≈ 2.5 minutes) to prevent reverts. New users with no existing storage skip the buffer since nothing is draining yet.

### Further Reading

- [Full Storage Cost API spec](https://hackmd.io/@lordforever/SJ6Lwv2dWx) (external): complete API specification for storage cost calculations
- [Filecoin Pay spec](https://github.com/FilOzone/filecoin-pay/blob/main/SPEC.md): full protocol specification
- [Filecoin Pay Technical Overview](/core-concepts/filecoin-pay-overview/): contract architecture deep-dive

## Next Steps

- [Storage Costs](/developer-guides/storage/storage-costs/): SDK API usage and code examples
- [Upload Pipeline](/developer-guides/storage/upload-pipeline/): Upload workflows from simple to advanced
- [Storage Operations](/developer-guides/storage/storage-operations/): Data set management, retrieval, and lifecycle
- [Filecoin Pay Technical Overview](/core-concepts/filecoin-pay-overview/): Contract internals and architecture