Challenge

# REST API

Verify a solution from any language with one HTTPS request. Send it from your server with the secret key of a Challenge configuration.

## Request

**Method**

`POST`

**URL**

`https://api.botpoison.com/verify`

Shell

```bash
curl --request POST \
  --url 'https://api.botpoison.com/verify' \
  --header 'accept: application/json' \
  --header 'content-type: application/json' \
  --header 'authorization: Bearer sk_xxxxxxxx' \
  --data '{"solution": "xxxxxxxx"}'
```

Send the key as an `Authorization: Bearer` header. Proxies and loggers already redact it. An `X-Api-Key` header works too, or `secretKey` in the body. If you send more than one, the body key wins, then the bearer token.

Send the body as JSON, or form-encoded with `Content-Type: application/x-www-form-urlencoded`, using the same parameter names.

### Body parameters

| Parameter | Type | Description |
| --- | --- | --- |
| solution Required | string | The _botpoison field your form sent. |
| secretKey Optional | string | The secret key of a Challenge configuration. Required unless you send it in an Authorization or X-Api-Key header. |

## Response

JSON

```json
// The status is 200 for every result. Read "ok" to decide whether to accept
// the submission. When "ok" is false, "message" says why.

// Accepted
{ "ok": true }

// Rejected, with the reason
{ "ok": false, "message": "Invalid solution" }
```

### Messages

| Message | Meaning |
| --- | --- |
| `Missing secret key` | No key in the body or the header. |
| `Missing solution` | The body has no solution. |
| `Test key` | The test key decided the result. See Test key below. |
| `Invalid secret key` | The key is unknown or rerolled, or belongs to a Classify configuration. |
| `Mismatching keys` | The solution was issued for another configuration. |
| `Invalid solution` | The solution is malformed or wrong. |
| `Invalid solution length` | The solution has the wrong number of parts. |
| `Invalid signature` | The challenge was not issued by Botpoison. |
| `Expired challenge` | The challenge was solved too long ago. |
| `Spent challenge` | The solution was already verified once. |
| `Internal server error` | The check failed on our side. Try again. |

One request is refused with a status of its own: a body larger than 1 MB answers 413 with the plain-text body `Payload Too Large` rather than JSON.

## Test key

With the secret key `test`, the solution decides the result.

JavaScript

```javascript
// The solution "ok" passes
const OK_REQUEST_DATA = { secretKey: "test", solution: "ok" }
const OK_RESPONSE = { ok: true, message: "Test key" }

// Any other solution fails
const NOT_OK_DATA = { secretKey: "test", solution: "nok" }
const NOT_OK_RESPONSE = { ok: false, message: "Test key" }
```

## If Botpoison is unreachable

The browser library cannot run the check, so the form fires `botpoison-challenge-error` instead of sending. Listen for it to show the visitor a message or another way to reach you.

On your server, a request that cannot reach us fails at the network, and a fault on our side answers `ok: false` with `Internal server error`. The Node library sets no timeout on `verify()`, so wrap the call in one of your own.

To accept submissions during an outage, key on those two outcomes only. Never accept a submission because its `_botpoison` field is missing: that is what every bot sends.
