> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zeroclick.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Integration overview

> The contract between ZeroClick and your API: what arrives on every forwarded request, your backend's four obligations, and the three refusals it must produce.

Agents buy and pay at your pay URL (`https://acme.pay.zeroclick.io`). ZeroClick verifies the payment, signs the request, and forwards it to your API at your configured upstream base URL. This page is the whole contract between ZeroClick and your backend. The [seller SDKs](/sdks/overview) implement it; the [REST walkthrough](/integrate/rest-walkthrough) shows how to implement it without one. If a purchase should leave something durable behind — an account, a subscription, an API key the buyer then uses with you directly — that is a separate, additive integration: [sell accounts and API keys](/integrate/stateful-sellers).

## What arrives on every forwarded request

ZeroClick sets three headers on each request it forwards:

| Header          | Value                                     | Purpose                                                                                                                                  |
| --------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `zc-request-id` | `zcreq_8h2m4x0q9k1f`                      | Correlation id. The same id flows through the probe, the challenge, the paid retry, the allowance check, and the usage record.           |
| `zc-agent-id`   | `agt_x7f2kq93bh0d`                        | The buyer. Absent or empty on signed anonymous probes, which are valid. See [verify requests](/integrate/verify-requests).               |
| `zc-signature`  | `t=<unix seconds>,kid=hsec_…,v1=<64 hex>` | HMAC-SHA256 proof that the request came through ZeroClick unmodified. Sandbox traffic appends `,sb=1` and adds a `zc-sandbox: 1` header. |

Before forwarding, ZeroClick strips all inbound `zc-*`, `x-payment`, and `payment*` headers and sets its own, so a caller can never inject them. Other request headers pass through untouched. Your API's own authentication remains whatever you configured between yourself and ZeroClick.

One more header matters to the contract without ever reaching you: `zc-mode`. A buyer sends `zc-mode: free` to the pay URL to opt a call into included-units coverage. ZeroClick consumes it there, and a missing or unrecognized value means paid. See [free and identity endpoints](/integrate/free-and-identity-endpoints). The full header reference is at [headers](/resources/headers).

## Optional end-to-end body encryption

An encrypted request arrives with `Content-Type: application/jose`. ZeroClick forwards the Compact JWE bytes but has no seller private key.

Verify the signature and check the allowance against the encrypted request. After an allow decision, decrypt the body inside your infrastructure.

Attach `zc-usage` to the application response before you encrypt its body for the buyer. The header remains visible for settlement.

See [end-to-end body encryption](/concepts/end-to-end-encryption) for the data path, key ownership, visible metadata, and fixed cipher suite.

## The four obligations

On every forwarded request, your backend must:

1. **Verify** the `zc-signature` against your signing secret, before anything else. Only ZeroClick-signed traffic reaches your handlers. See [verify requests](/integrate/verify-requests).
2. **Check the allowance** with `POST /v1/usage/check`: does the buyer's plan cover what this request will use? See [check allowances](/integrate/check-allowances).
3. **Serve** the request as your API normally would.
4. **Settle** what the request used: a `zc-usage` header on the successful response, or an asynchronous usage report. See [settle usage](/integrate/settle-usage).

With an SDK, the first two obligations are one `guard` call and the fourth is one helper:

<CodeGroup>
  ```ts TypeScript theme={null}
  const decision = await zeroClick.guard(request, {
    serviceSlug: "product-watch",
    usage: [{ meterSlug: "requests", quantity: 1 }],
  });
  if (decision.action === "deny") return decision.response;

  const response = Response.json({ watching: true });
  return zeroClick.withUsage(response, [
    { serviceSlug: "product-watch", meterSlug: "requests", quantity: 1 },
  ]);
  ```

  ```python Python theme={null}
  zc_request = zc_request_from_asgi_scope(request.scope, await request.body())

  decision = await zeroclick.guard(
      zc_request,
      service_slug="product-watch",
      usage=[UsageItem(meter_slug="requests", quantity=1)],
  )
  if decision.action == "deny":
      return to_fastapi(decision.response)

  return to_fastapi(
      zeroclick.with_usage(
          ZcResponse.json({"watching": True}),
          [SyncUsageItem(service_slug="product-watch", meter_slug="requests", quantity=1)],
      )
  )
  ```

  ```go Go theme={null}
  // Meter verifies the signature, checks the allowance, refuses before the
  // handler runs, and settles the zc-usage header on a delivered 2xx.
  mux.Handle("/v1/product-watch", seller.Meter(sellers.PerRequest("requests", 1))(
  	http.HandlerFunc(productWatch)))
  ```
</CodeGroup>

## The three refusals

When your API cannot serve, it must answer ZeroClick with one of exactly three responses. The SDKs build all of them. A deny decision carries the response ready to return.

| Status | When                                                                    | Exact body                                                                                                   |
| ------ | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `401`  | The signature is missing, malformed, stale, or invalid.                 | `{"error":"invalid_zeroclick_signature"}`                                                                    |
| `402`  | The allowance check denies, or an unpaid request needs payment.         | `{"error":"payment_required","serviceSlug":"product-watch","usage":[{"meterSlug":"requests","quantity":1}]}` |
| `503`  | The allowance API is unreachable and your outage policy is fail-closed. | `{"error":"allowance_unavailable"}`                                                                          |

The `402` body is not an error page. It is data. ZeroClick reads the usage list, prices it from your catalog, and issues the buyer a signable payment challenge. The buyer never sees your body. A `402` with `usage: []` means "free, but identity-scoped", which ZeroClick answers with a \$0 identity challenge. The [errors](/resources/errors) page lists error codes across the platform.

## What never to do

* **Never serve unverified traffic.** Your upstream URL is reachable; the signature is the gate. A request with no ZeroClick headers must get the `401`, not your handler.
* **Never bill on a non-2xx.** `zc-usage` belongs on 2xx responses only: a 4xx is the buyer's bad input and a 5xx is your failure. Neither delivered anything worth charging for.
* **Never price or cache challenges yourself.** Your `402` declares usage quantities, not prices. ZeroClick prices each refusal from your catalog per request and binds each challenge to that exact request. A cached price or replayed challenge cannot settle.

## Let the forwards reach your API

ZeroClick forwards from its own servers, with no fixed IP range, and the `User-Agent` on a forward is the buyer's. A firewall or bot-protection layer in front of your upstream base URL (Vercel Firewall, Cloudflare, and similar) can answer a forward with an HTML challenge, which ZeroClick relays to the buyer as a failed purchase. Exempt requests that carry `zc-signature` on the paths ZeroClick calls. The guard still verifies every one of them. See [firewalls and bot protection](/integrate/firewalls-and-bot-protection).

## SDK or REST

If your backend is TypeScript, Python, Go, or Ruby, use the SDK. It implements the contract, including the denial bodies and the signature edge cases:

* [TypeScript quickstart](/sdks/typescript/quickstart): `@zeroclickai/sellers` on npm
* [Python quickstart](/sdks/python/quickstart): `zeroclick-sellers` on PyPI
* [Go quickstart](/sdks/go/quickstart): `cdn.zeroclick.io/sdks/sellers-go`

Otherwise the contract is small enough to implement over REST: two API calls, one signature check, three fixed response bodies. Start at the [REST walkthrough](/integrate/rest-walkthrough) and the byte-level [signature spec](/integrate/signature-spec).

## Work through the contract

<Columns cols={2}>
  <Card title="Keys and secrets" icon="key" href="/integrate/keys-and-secrets">
    The three runtime keys, scopes, split read/write keys, and rotation.
  </Card>

  <Card title="Verify requests" icon="shield-check" href="/integrate/verify-requests">
    What verification proves, anonymous probes, and the raw-path rule.
  </Card>

  <Card title="Firewalls and bot protection" icon="brick-wall" href="/integrate/firewalls-and-bot-protection">
    Exempt signed forwards from bot challenges without weakening the guard.
  </Card>

  <Card title="Check allowances" icon="list-checks" href="/integrate/check-allowances">
    Guard semantics, usage items, denials, and the outage policy.
  </Card>

  <Card title="Settle usage" icon="receipt" href="/integrate/settle-usage">
    The `zc-usage` header and asynchronous usage reports.
  </Card>

  <Card title="Charge up to a maximum" icon="gauge" href="/integrate/charge-up-to-a-maximum">
    Use ceilings to bill work you can't size up front.
  </Card>

  <Card title="Free and identity endpoints" icon="id-card" href="/integrate/free-and-identity-endpoints">
    Endpoints that cost nothing but must know the buyer.
  </Card>

  <Card title="Sell accounts and API keys" icon="key-round" href="/integrate/stateful-sellers">
    Turn a purchase into a durable account, credit balance, and API key.
  </Card>
</Columns>
