# Operations and reliability

## Runtime readiness

Call `GET https://app.cleanedweb.com/v1/capabilities` before planning a workflow. Treat a
market as ready only when it appears in `available_markets`. A `503` means readiness is
unknown; it is not a zero-result response.

Authenticated `GET /v1/markets` narrows runtime-ready markets to the current workspace.
Static coverage, pricing, and documentation never override these two runtime surfaces.

## Limits

Use `capabilities.limits` as current truth for location suggestions, recommended interactive
limits, machine search ceilings, and request-rate limits. A machine search must always use a
positive bounded `limit` and `max_units`, even when a static example shows another value.

Bounded searches expose `has_more` and an opaque signed `next_cursor`. Send that cursor
with the unchanged query and a positive `limit` to read the next page. A
`snapshot_changed` response means the maintained projection advanced; restart from the
first page. An omitted limit still streams every match.

Use `POST /v1/properties/count` when only an exact total is required. It applies
the same filters without transferring rich property records, returns the
projection identity with the total, and consumes no delivery Units. The server
caches the result only within that projection generation; a rebuilt projection
forces a fresh count.

## Retry matrix

| Outcome | Retry? | Required action |
| --- | --- | --- |
| Network failure before a response | Bounded | Preserve body and idempotency key |
| `429 rate_limited` | Yes | Wait for `Retry-After`; preserve idempotency key |
| `503 service_unavailable` | Bounded | Exponential backoff with jitter |
| `401`, `402`, `403`, `404` | No | Restore auth, Units, entitlement, or identifier |
| `409 max_units_exceeded` | No | Narrow request or obtain approved new ceiling |
| `409 idempotency_conflict` | No | Do not reuse the key for a changed request |
| `422` validation or location error | No | Correct input or obtain user choice |

A reasonable transient schedule is 1, 2, 4, 8, then 16 seconds with jitter, followed by a
surfaced failure. Do not create an unbounded retry loop.

## Metering and receipts

Read Unit rates from `capabilities.unit_costs`. An empty object means machine charging is not
published as ready. Every successful machine search returns a durable usage receipt plus
request ID, Units, and balance headers. Store those identifiers with the downstream batch.

Exact retries inside the published idempotency window return the committed receipt without
charging again. A changed payload with the same key fails. The current OpenAPI description
states a 24-hour request-key window; clients must treat the deployed OpenAPI contract as
authoritative if that value changes.

## Freshness and latency

`snapshot.dataUpdatedAt` describes the maintained projection, not response latency or the
freshness of every contributing source. Consumers must define their own acceptable maximum
age and stop or request approval when the response exceeds it.

No numeric public response-time or availability SLA is established by this guide. Do not
invent one from a successful health probe or a single request.

## Support evidence

For an operational escalation, retain:

- workspace ID;
- UTC timestamp;
- endpoint or MCP tool name;
- `X-CleanedWeb-Request-Id` or usage `requestId`;
- stable error code and HTTP status;
- whether the request was an exact idempotent retry;
- redacted request shape and market.

Do not attach API keys, session cookies, signing secrets, full contact data, or unredacted
property payloads unless a separately approved secure channel requires them.
