# Demo pages API

> The public demo and CAPTCHA test pages: checking a token from one of their Cloudflare Turnstile widgets with Cloudflare's siteverify, and whether a request carried a Cloudflare clearance. Public, with no key or session; nothing here solves anything.

Source: https://zerocaptcha.io/docs/reference/api/demo

## Check for a Cloudflare clearance

`GET /v1/demo/clearance` (`getDemoClearance`)

Says whether this request carried a `cf_clearance` cookie, the one
Cloudflare sets once a challenge, or a Cloudflare Turnstile widget with
pre-clearance, is passed, and whether it came through Cloudflare's
network. The demo challenge pages call it from the browser, which sends
the cookie that page scripts may not be able to read. The cookie's value
is never read out, logged or kept, and only Cloudflare can say whether it
is still valid. It needs no key or session. Requests have the budget per
client address that public reads share. Never cached.

Responses:

- 200 OK: What the request carried.
- 429 Too Many Requests: Too many requests from this address (`rate_limited`).
- 503 Service Unavailable: The budget could not be checked now (`service_unavailable`). Retry shortly.
- Any other status: An error, as RFC 9457 problem details.

```bash
curl https://api.zerocaptcha.io/v1/demo/clearance
```

```js
const response = await fetch("https://api.zerocaptcha.io/v1/demo/clearance");
console.log(response.status, await response.text());
```

```python
import requests

response = requests.get(
    "https://api.zerocaptcha.io/v1/demo/clearance",
    timeout=30,
)
print(response.status_code, response.text)
```

## Check a demo token

`POST /v1/demo/verify` (`verifyDemoToken`)

Asks Cloudflare's siteverify about a token from one of the demo pages'
Cloudflare Turnstile widgets, with that widget's secret, and returns the
verdict as it came: success, the hostname, the action, the cData and the
error codes. Solves nothing: bring a token a widget gave, in a browser or
through a task. A token passes siteverify once, within 300 seconds of the
solve. It needs no key or session. A browser's request must send no
`Sec-Fetch-Site` but `same-origin` or `none` (`csrf_rejected`). Checks
have a budget per client address. The token is never logged or kept.

Body fields:

| Field | Type | Required | What it is |
| --- | --- | --- | --- |
| `token` | string | yes | The token: the widget's `cf-turnstile-response`, or the `token` a Cloudflare Turnstile task returned for the page, up to 2,048 characters. |
| `widget` | DemoWidget | yes | The demo widget the token came from. |

Responses:

- 200 OK: Cloudflare's verdict, a failing one included.
- 403 Forbidden: A browser's request from another site (`csrf_rejected`).
- 422 Unprocessable Content: An unknown widget, or no token, or not one siteverify takes (`validation_failed`).
- 429 Too Many Requests: Too many checks from this address (`rate_limited`).
- 503 Service Unavailable: Cloudflare's siteverify did not answer, or this server does not serve the demo (`service_unavailable`). Retry shortly.
- Any other status: An error, as RFC 9457 problem details.

```bash
curl -X POST https://api.zerocaptcha.io/v1/demo/verify \
  -H "Content-Type: application/json" \
  -d '{
  "token": "token",
  "widget": "managed"
}'
```

```js
const response = await fetch("https://api.zerocaptcha.io/v1/demo/verify", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "token": "token",
    "widget": "managed"
  }),
});
console.log(response.status, await response.text());
```

```python
import requests

response = requests.post(
    "https://api.zerocaptcha.io/v1/demo/verify",
    json={
        "token": "token",
        "widget": "managed",
    },
    timeout=30,
)
print(response.status_code, response.text)
```
