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

# Report a page view over REST

> Send one page-content request to POST /v1/page-views from any stack: the key scope, the request body, the fire-and-forget 204, and the errors.

`POST /v1/page-views` records one page view. Use it from any language or framework that has no [SDK middleware](/docs/page-views/sdk-middleware.md): call it once per page-content `GET` your site serves, from the request that serves it. It answers `204` without waiting for anything downstream, so a report never sits on your response.

## Mint a key

Reporting authenticates with a `zc_` key carrying the [`page-views:write` scope](/docs/page-views/overview#the-page-views-key-scope). In the [dashboard](https://dashboard.zeroclick.io) under **Settings → API keys**, create a key with the **Page views** group's **Write** toggle enabled, and keep it on your marketing site's server.

## Report a view

```sh theme={null}
curl -sS -X POST https://api.zeroclick.io/v1/page-views \
  -H "Authorization: Bearer $ZEROCLICK_PAGE_VIEWS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "seller": "sel_your_seller_id",
    "path": "/pricing",
    "status": 200,
    "capturedAt": "2026-08-26T17:00:00.000Z",
    "userAgent": "Mozilla/5.0 (compatible; GPTBot/1.1; +https://openai.com/gptbot)",
    "accept": "text/markdown, text/html",
    "clientIp": "203.0.113.7",
    "country": "US",
    "referrerHost": "www.google.com"
  }'
```

A success is an empty `204`.

## Request body

Report only page-content `GET` requests (the same thing a reader loads to view a page), so there is no method field; the method is always `GET`.

| Field | Type | Required | Notes |
| - | - | - | - |
| `seller` | string | yes | The seller whose site served the page (its public `sel_…` id). |
| `path` | string | yes | The request path, starting with `/`. Send the path only; any query string or fragment is dropped on our side. |
| `status` | number | no | The response status you served (100–599). |
| `durationMs` | number | no | How long the request took, in milliseconds. |
| `capturedAt` | string | no | When your edge observed the request (ISO 8601). Omit it rather than guessing; it is never invented on our side. |
| `journeyId` | string | no | A [reading-chain id](/docs/page-views/overview.md#journey-stitching) that ties this view to an agentified read, when the request carried one. |
| `representation` | string | no | What your site served for this request: `html` or `markdown`. The [SDK middleware](/docs/page-views/sdk-middleware.md) derives it from the response content-type; set it yourself when you report by hand. Lets analytics segment journeys by whether the entry got the agent experience. |
| `userAgent` | string | no | The visitor's `User-Agent`. Read to derive the viewer id and classify the viewer, then discarded, never stored raw. |
| `accept` | string | no | The visitor's `Accept` header, which sharpens agent detection. |
| `clientIp` | string | no | The visitor's IP. Combined with the user-agent into the anonymous viewer id and never stored raw. |
| `country` | string | no | The edge's Cloudflare `cf-ipcountry` value. Clamped to a 2-letter ISO code on our side; sentinels like `XX` are dropped. |
| `referrerHost` | string | no | The referrer's host, e.g. `www.google.com`. Send the host only; if you send a full URL we reduce it to the host, but the referrer's path and query should never leave your site. |
| `evalTag` | string | no | The request's `x-zeroclick-eval` header, as received, when one of ZeroClick's own eval runs loaded the page (1 to 512 characters). |
| `evalSignature` | string | no | The request's `x-zeroclick-eval-signature` header, as received (1 to 1024 characters). Sent with `evalTag`. |
| `evalSignatureInput` | string | no | The request's `x-zeroclick-eval-signature-input` header, as received (1 to 1024 characters). Sent with `evalTag`. |
| `evalSignatureAgent` | string | no | The request's `x-zeroclick-eval-signature-agent` header, as received (1 to 512 characters). Sent with `evalTag`. |
| `host` | string | no | The host the page was requested on, as the JS `URL.host` reads it: the hostname and any non-default port (1 to 300 characters). Sent with `evalTag`; the signature is verified against it. |
| `source` | string | no | The request's `src` query value when it is ZeroClick's own check marker: `ze-` followed by the run, a slug of up to 32 characters. How a check that runs inside a browser agent's cloud, which cannot sign, is told apart. Sent with `host`. Send no other query value. |
| `sourceSignature` | string | no | The request's `signature` query value beside a `source` marker, as received (1 to 256 characters). Accepted and not checked yet; ZeroClick is adding signed markers. |

Forward the visitor's `userAgent`, `accept`, and `clientIp` from the original request, not your server's: the request reaches ZeroClick from your backend, so its own headers describe your server, not the reader. Report only what a reader loads to view a page; skip assets and redirects, exactly as the [middleware does](/docs/page-views/sdk-middleware.md).

The last seven fields describe ZeroClick's own checks, and the middleware forwards them for you. A value past its limit fails validation for the whole report, so leave a field out rather than truncate it. A tagged view is labeled as one of ZeroClick's checks, and kept out of your numbers, only when the signature verifies over `host`; a forged tag changes nothing. The marker is unsigned, so a forged one only keeps that visit out of your own numbers.

## Response and errors

| Status | Meaning |
| - | - |
| `204` | Recorded. The body is empty. |
| `400` | The body failed validation (for example a `path` that does not start with `/`). |
| `403` | The key is missing the `page-views:write` scope, or resolves to no organization. |
| `404` | `seller` does not name a seller in the key's organization. |
| `429` | Per-organization rate limit exceeded. |

Reporting is fire-and-forget by design: send the beacon without blocking your response, and treat any failure as a no-op so a reporting problem never affects the page. The [SDK middleware](/docs/page-views/sdk-middleware.md) does exactly this for you.

## Next steps

> **[SDK middleware](/docs/page-views/sdk-middleware.md)**
>
> Report automatically from your own site (TypeScript, Python, Go, or Ruby), fail-open.

> **[Overview](/docs/page-views/overview.md)**
>
> What is captured, how viewers are classified, and the privacy model.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.