> ## 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.

# Free and identity endpoints

> Serve endpoints that cost nothing but must know which buyer is calling, and understand how included free units reach your API.

Some endpoints cost nothing but still must know who is asking: polling a job the buyer created, reading account limits, any read or write served only to the buyer that owns the underlying records. Guarding them with `guard` would demand payment for free work; skipping the guard entirely would serve them to anyone. The identity guard is the middle path: it verifies the signature exactly like `guard`, requires a proven buyer, and makes no allowance call.

## Guard identity, not allowance

<CodeGroup>
  ```ts TypeScript theme={null}
  export async function GET(request: Request) {
    const decision = await zeroClick.guardIdentity(request, {
      serviceSlug: "product-watch",
    });
    if (decision.action === "deny") return decision.response;

    const jobId = new URL(request.url).pathname.split("/").pop();
    const job = await findJob(jobId, { owner: decision.context.zcAgentId });
    if (!job) return Response.json({ error: "not_found" }, { status: 404 });
    return Response.json(job);
  }
  ```

  ```python Python theme={null}
  @app.get("/v1/jobs/{job_id}")
  async def job_status(request: Request, job_id: str) -> Response:
      zc_request = zc_request_from_asgi_scope(request.scope, await request.body())

      # Synchronous even on the async client: no network call, nothing to await.
      decision = zeroclick.guard_identity(zc_request, service_slug="product-watch")
      if decision.action == "deny":
          return to_fastapi(decision.response)

      return to_fastapi(
          ZcResponse.json({"jobId": job_id, "owner": decision.context.zc_agent_id})
      )
  ```

  ```go Go theme={null}
  mux.Handle("/v1/limits", seller.Identify()(http.HandlerFunc(limits)))

  func limits(w http.ResponseWriter, r *http.Request) {
  	zc, _ := sellers.FromContext(r.Context())
  	w.Header().Set("content-type", "application/json")
  	json.NewEncoder(w).Encode(map[string]any{"zcAgentId": zc.AgentID})
  }
  ```
</CodeGroup>

The decision works like `guard`'s:

* A failed signature is the usual `401` deny: unverified traffic never reaches free endpoints either.
* A verified request **with** `zc-agent-id` allows, with allowance status `not_required` and the buyer in `context`. Scope your reads and writes to that id.
* A verified request **without** a buyer, a [signed anonymous probe](/integrate/verify-requests#signed-anonymous-probes-are-valid), denies with reason `identity_required` and this exact body:

```json theme={null}
{ "error": "payment_required", "serviceSlug": "product-watch", "usage": [] }
```

The empty usage list is meaningful: it tells ZeroClick the call costs nothing and the missing piece is identity. ZeroClick answers the agent with `401 bearer_required` and a pointer to its registration recipe, and the retry arrives with the buyer's `zc-agent-id` attached. No payment is involved.

## Identity and access are separate

A buyer that has registered holds an identity; billing needs an access grant on top of it. A purchase creates access, and allowance checks and usage reports draw against it (see [agents and access](/concepts/agents-and-access)). Reporting usage against an identity-only buyer fails with `access_not_found`. Keep the division clean: `guardIdentity` for free identity-scoped calls, `guard` for anything billable.

The same division applies to settlement: no `zc-usage` belongs on a free response. There is nothing to settle. Free means free.

## Included free units

There is a second kind of free: a plan's meter price can grant `includedUnits`, free units per period, configured in your catalog (see [plans and pricing](/concepts/plans-and-pricing)). These are billable meters whose first units cost nothing, not identity-scoped endpoints, and they reach your API through the normal guard path:

* **The buyer opts in per call** by sending `zc-mode: free` to the pay URL. ZeroClick operates paid-by-default: a missing or unrecognized mode means paid. The proxy consumes the header and never forwards it to you.
* **The free allowance needs no funding, but it does need a claimed agent.** Free units are served only to an agent identity that a human has claimed with a verified email. An unclaimed agent, or one whose claim carries no verified email, gets no free units - its free-mode calls are refused like any unpaid call. A claim with a verified email, rather than a payment, is what stands between a new agent and its free units.
* **Free calls require an identified caller.** Included-units coverage is per buyer - aggregated across every agent that human has claimed - so ZeroClick answers an unidentified free-mode call with `401 bearer_required` and its registration-and-claim recipe. The identified retry re-runs the real coverage check, including the claimed-and-verified requirement.
* **Your integration does not change.** Guard the route and settle usage exactly as for paid traffic. For a covered free-mode call, the allowance check answers `allowed`, and the usage you settle draws down the buyer's included allowance instead of charging.

That symmetry is the point of the guard: paid, ceiling, included-free, and identity-only traffic all arrive as signed requests. The same four obligations (verify, check, serve, settle) handle every one. Back to the [integration overview](/integrate/overview) for the full contract, or on to [settle usage](/integrate/settle-usage) if you came here mid-integration.
