# Bot protection

**Not built.** This page is the design; Jadpo doesn't do this yet. See [What is built](/docs/built-in-services-built.md).

Bot protection stops scripts from using a public form, such as a sign-up
or a demo request. The browser shows a challenge widget, and your app
checks the token it gives. `bot_check` is a capability with one
operation, checking a token: pass or fail. A package fills it, such as
Cloudflare Turnstile, hCaptcha or reCAPTCHA, and you name its connection
in `application { }`. A route, or a generated feature, asks for the
check with `bot_check: true`.

Not built yet: `bot_check:` is `toolchain.not_built_yet` where it is written, so
this is the design:

```jadpo
// app.jadpo
application {
    connections: {
        turnstile: {
            package: Turnstile.v0
            credential: config.turnstile_secret
        }
    }
    bot_check: {
        connection: turnstile
    }
}

// domains/sales/routes/demo_requests.jadpo
POST / {
    authentication: RouteAuthentication.none
    input: DemoForm
    output: DemoReceived
    status: SuccessStatus.created
    run: request_demo(input)
    bot_check: true
}
```

- **Jadpo's own public endpoints are checked too,** the magic-link and
  privacy requests, whenever `bot_check:` names a connection.
- **The frontend shows the widget.** The token travels in the
  `X-Bot-Check` header, never in the route's input, and is checked
  before the action runs, within the request's deadline.
- **A failed check** is the built-in failure `bot_check_failed` (403),
  worded from translations like every failure
  ([Failures for client apps](/docs/failures-for-client-apps.md)).
- **reCAPTCHA's score** gets a threshold setting on its connection.
- **An unreachable provider refuses the request,** so the check fails
  closed. Letting requests through while it is down needs an
  [acceptance](/docs/acceptances.md), listed in the
  approval report.
- **Development and tests pass every check** through a local driver,
  and a test can script `bot_check_failed`
  ([Fakes for integrations](/docs/fakes-for-integrations.md)).
- `bot_check: true` with no `bot_check:` connection is a compile error
  naming the setting to add.

An app that needs a check today takes the widget's token in the route's input, describes
the challenge service as a package
([Call an outside API](/guides/guide-call-an-outside-api.md)), and calls it first
in the action. Every public route already has a [rate limit](/docs/rate-limits.md),
which slows a script but does not stop one.
