# Metering & usage

ZeroClick bills buyers based on the usage you report. There are two ways to
report it: synchronously on each proxied response, or asynchronously in
batches. There is one contract for signaling that a buyer's meter is
exhausted.

## Check before you act

Before performing a paid action for a ZeroClick buyer, confirm the action is
still covered by their plan. If it isn't, don't perform the action. Return
the [402 exhaustion response](#when-a-meter-is-exhausted) instead, so the
agent knows to extend the plan and retry.

ZeroClick does not block requests at the proxy. Your API is the enforcement
point: you are the only party that knows the cost of an action before running
it, so the exhausted response always comes from you. When a spend cap is
reached, ZeroClick notifies you and the buyer, and your API stops serving
paid actions until the plan is extended.

## Reporting usage

Add an `X-ZeroClick-Usage` header to responses on your paid endpoints. The
value is a comma-separated list of `meter=quantity` pairs, using each meter's
kebab-cased label:

```http
HTTP/1.1 200 OK
Content-Type: application/json
X-ZeroClick-Usage: api-requests=1, compute-seconds=4

{ "result": "..." }
```

ZeroClick reads the header as the response passes through the proxy and
records the usage automatically. Use sync reporting when the cost of a
request is known by the time you respond.

The header is stripped before the response reaches the buyer.

Send batched usage events to ZeroClick on your own cadence:

`POST https://pay.zeroclick.io/v1/usage/batch`

Authenticate with your service API key from the dashboard
(`Authorization: Bearer {service-api-key}`).

```json
{
	"events": [
		{
			"userId": "user_8f3kz1",
			"meter": "compute-seconds",
			"quantity": 42,
			"timestamp": "2026-06-12T09:30:00Z",
			"idempotencyKey": "job-7841-completed"
		}
	]
}
```

Delivery is at-least-once: if a batch times out, send it again. ZeroClick
deduplicates on `idempotencyKey`, so retries never double-bill. Batches are
limited to 1,000 events; send multiple batches for more.

Prefer async reporting for long-running jobs, websockets and streams, or
backfilling usage your sync headers missed.

You can combine both: report request-shaped usage with headers and report
job-shaped usage in batches. The same meter must only be reported through one
channel per action, or it will be counted twice.

## When a meter is exhausted

When a buyer's plan can't cover an action, respond with
`402 Payment Required` and a reason header:

```http
HTTP/1.1 402 Payment Required
X-ZeroClick-Reason: usage_exhausted
```

| Reason | Meaning |
| --- | --- |
| `usage_exhausted` | The plan's included or purchased units for a meter are used up. |
| `spend_cap_reached` | The plan's spend cap for the current period has been hit. |
| `plan_expired` | The plan has ended and hasn't been renewed. |

When the agent receives a 402 with one of these reasons, ZeroClick directs it
to extend the plan:

`POST https://{service-slug}.pay.zeroclick.io/extend`

After a successful extension the agent retries the original request, so make
sure a 402 response has no side effects. The action should be safely
repeatable once the plan is topped up.
