---
title: Meter
description: Post-paid metered pricing on a Gate paywall. The buyer signs a spending ceiling once, your upstream reports the actual work in a response header, and the difference is refunded on-chain automatically.
---

import { Callout } from "fumadocs-ui/components/callout";

# Meter

<Callout title="Beta" type="warn">
Meter is merged and in beta while final mainnet validation completes. Gate's
flat, tiered, and dynamic pricing models are live. Build against Meter now, but
treat the metered lane as beta until validation closes.
</Callout>

Some calls cost you more than others. A short completion and a long one are not
the same work, and pricing both at the same flat rate means you either overcharge
the cheap call or eat the expensive one.

**Meter** prices a [Gate](/docs/concepts/gate) paywall after the call instead of
before it. The buyer authorizes a ceiling up front, your upstream reports what
the request actually cost, and Meter refunds the difference on-chain. Set
`pricing_model: "metered"` on the paywall to turn it on.

## The flow

```
agent ──GET──▶ gw.codespar.dev/<slug> ──▶ 402 advertising the CEILING
      ◀──────────────────────────────────────┘
agent ──GET + signed ceiling──▶ gw.codespar.dev/<slug>
                                │ settle the ceiling on Base
                                │ proxy to your upstream
                                │ read the units header off the response
                                │ actual = base × multiplier
                                │ refund (ceiling − actual) to the payer
                                └──▶ 200 + data
```

## The ceiling

The 402 challenge advertises a **spending ceiling**, not the final price:

```
ceiling = base price × max multiplier
```

The payer signs that ceiling once, as a single EIP-3009 authorization on USDC over
Base. Signing happens before your upstream has done any work, so the ceiling is
the most the caller can ever be charged for the request. There is no second
signature and no follow-up approval.

## Reporting actual usage

After the payment settles, Meter proxies the call to your upstream and reads a
multiplier from a **response header you configure**. Your service decides what
the number means; Meter only multiplies by it.

```json
{
  "pricing_model": "metered",
  "metered_config": {
    "basis": "complexity",
    "base_atomic": "10000",
    "min_mult": 1.0,
    "max_mult": 3.5,
    "units_header": "X-Complexity"
  }
}
```

| Field | What it sets |
|---|---|
| `basis` | What the multiplier measures: `complexity`, `tokens`, `time`, or `units`. Informational, it labels the receipt |
| `base_atomic` | The base price in atomic USDC (6 decimal places) before the multiplier |
| `min_mult` / `max_mult` | The clamp. `ceiling = base_atomic × max_mult` |
| `units_header` | The response header your upstream reports the multiplier in, for example `X-Complexity` |

A response that reports `X-Complexity: 2.0` against a `base_atomic` of `10000`
(that is $0.01) is charged $0.02, against a signed ceiling of $0.035.

## Fail-safe pricing

The actual charge is always clamped into the configured range:

```
actual = base_atomic × clamp(multiplier, min_mult, max_mult)
```

A missing header, a malformed value, or a non-positive number falls back to the
**minimum** multiplier, not the maximum. A silent upstream charges the buyer the
least, so a bug in your service can never overcharge a caller. To charge more
than the floor, your upstream has to say so explicitly.

The clamp also means the actual charge can never exceed the ceiling the payer
signed, whatever the header claims.

## The refund

The difference between the ceiling and the actual charge goes back to the payer
on-chain, automatically, with no action from either side:

```
refund = ceiling − actual
```

The refund is claimed before it is sent and keyed on the settlement transaction,
so a crash mid-flight never double-refunds. A background pass reconciles anything
left in flight: it re-sends a stale claim and confirms a broadcast transaction
against chain state, because a broadcast is not yet a refund.

Sub-cent dust is the one exception. Below a small threshold an on-chain refund
costs more in gas than it returns, so it is **waived and recorded** rather than
sent. The waiver is written down; it does not vanish.

## The receipt

The receipt is sealed at the ceiling during settlement, then re-sealed once the
call is metered, carrying all three amounts:

| Field | Meaning |
|---|---|
| `authorized` | The ceiling the payer signed |
| `charged` | What the call actually cost |
| `refunded` | What went back on-chain |

Alongside them, `metering` records the `basis`, the reported `units`, and the
`unit_price`. The hash chain is rebuilt and re-signed on the update, so the
[audit chain](/docs/concepts/audit-chain) still verifies end to end.

## Reading earnings

`GET /v1/paywalls/:id/stats` reports the ceiling and the actual side by side:

```json
{
  "settled_count": 128,
  "gross": "4.48",
  "refunded": "1.92",
  "net": "2.56"
}
```

`gross` is the sum of the ceilings payers authorized, `refunded` is what went
back to them, and `net` is what you actually earned. On a metered paywall the
gap between `gross` and `net` is the feature working, not revenue lost.

## Related

- [Gate](/docs/concepts/gate): the x402 gateway a metered paywall runs on.
- [Paywalls API](/docs/api/paywalls): `pricing_model` and the full field reference.
- [Audit chain](/docs/concepts/audit-chain): how the re-sealed receipt stays verifiable.
