Client API: Wicket
Wicket checks that a person is filling in a form.
Wicket checks that a person is filling in a form. Make widgets and read how they do: their hostnames, modes, secret keys and the numbers over time. Your server verifies a token the widget puts in the form with the secret key.
Base URL: https://api.coritan.com/api/v1. Paths below are complete.
To try these requests in the browser, open the interactive Client API reference.
Operations
Section titled Operations| Method | Path | Summary |
|---|---|---|
| GET | /api/v1/client/wicket/summary |
Widgets summary |
| GET | /api/v1/client/wicket/widgets |
List your widgets, with how each did in the last 24 hours and why any needs a look |
| POST | /api/v1/client/wicket/widgets |
Add a widget |
| GET | /api/v1/client/wicket/widgets/{widget_id} |
Get widget |
| PATCH | /api/v1/client/wicket/widgets/{widget_id} |
Change a widget's name, hostnames, mode, appearance or branding |
| DELETE | /api/v1/client/wicket/widgets/{widget_id} |
Delete a widget |
| GET | /api/v1/client/wicket/widgets/{widget_id}/analytics |
Widget analytics |
| POST | /api/v1/client/wicket/widgets/{widget_id}/secret |
Make a new secret key for a widget |
| POST | /api/v1/wicket/feedback |
Tell Wicket what a passed check turned out to be |
| POST | /api/v1/wicket/siteverify |
Check a token the widget put in your form |
Widgets summary
Section titled Widgets summaryGET /api/v1/client/wicket/summary
A short summary of Wicket on your account: how many widgets you have and your plan's limit, the checks started and passed in the last 24 hours, and each widget that needs a look with the reason.
Authentication: an access token, sent as Authorization: Bearer <token>.
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
Fields of a 200 response:
| Field | Type | Description |
|---|---|---|
widgets |
integer | |
limit |
integer | How many widgets your plan allows. -1 is unlimited. |
issued_24h |
integer | |
passed_24h |
integer | |
solve_rate_24h |
number or null | |
attention |
array of AttentionItem | |
attention[].widget_id |
integer | |
attention[].name |
string | |
attention[].reason |
string | disabled, not_verifying or hostname_refused. |
attention[].disabled_reason |
string or null | For the disabled reason only: why our team turned the widget off. Null for the other reasons. |
List your widgets, with how each did in the last 24 hours and why any needs a look
Section titled List your widgets, with how each did in the last 24 hours and why any needs a lookGET /api/v1/client/wicket/widgets
List your widgets, with how each did in the last 24 hours and why any needs a look.
The answer holds one page, how many widgets match over every page, how many widgets your plan allows, and the totals for your whole account.
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
q |
query | string or null | no | Only widgets whose name, site key or one of whose hostnames contains this text, ignoring case. |
status |
query | string | no | Which widgets to list: all (the default), active, disabled (turned off by our team) or attention (disabled, not verifying tokens, or refused for a hostname). Any other word answers 422. Default: all. |
sort |
query | string | no | The order: name, created, challenges (in the last 24 hours) or solve_rate (in the last 24 hours), each with a leading - for descending. The default is -created, newest first. A widget with no challenges in 24 hours has no solve rate and comes last. Any other word answers 422. Default: -created. |
page |
query | integer | no | The page, starting at 1. Default: 1. |
per_page |
query | integer | no | Widgets on a page, at most 100. Default: 24. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Fields of a 200 response:
| Field | Type | Description |
|---|---|---|
items |
array of WidgetSummary | |
items[].id |
integer | |
items[].name |
string | |
items[].site_key |
string | The public key your page puts in the widget. It starts with wk_. |
items[].mode |
string | managed, non_interactive or invisible. |
items[].status |
string | active, or disabled when our team turned the widget off. |
items[].branded |
boolean | Whether you chose to show Wicket's name on the widget. |
items[].hostnames |
array of string | The first three hostnames. hostname_count is how many the widget lists. |
items[].hostname_count |
integer | |
items[].created_at |
string | |
items[].last_challenge_at |
string or null | When the widget last started a challenge, to the minute. |
items[].stats_24h |
Stats24h | |
items[].attention |
array of string | Why the widget needs a look, if it does: disabled (our team turned it off), not_verifying (20 or more passes in 24 hours and your server verified none) or hostname_refused (a challenge came from a page whose hostname the widget does not list). |
items[].disabled_reason |
string or null | Why our team turned the widget off, or null when it is not turned off. |
total |
integer | How many widgets match q and status, over every page. |
page |
integer | |
per_page |
integer | |
limit |
LimitUsed | |
limit.used |
integer | |
limit.limit |
integer | -1 is unlimited. |
stats |
ListStats | |
stats.issued_24h |
integer | |
stats.passed_24h |
integer | |
stats.solve_rate_24h |
number or null | |
stats.attention |
array of AttentionItem | Every widget of the account that needs a look, one entry for each reason, not only the widgets on this page. |
Add a widget
Section titled Add a widgetPOST /api/v1/client/wicket/widgets
Add a widget. The answer holds the widget and its secret key, which is shown once and cannot be read again, so save it now.
Answers 402 when your plan has no room for another widget, for that many hostnames on one widget, or for turning Wicket's name off. Answers 422 for a name, mode, hostname or appearance setting Wicket refuses, and the message names it.
Authentication: an access token, sent as Authorization: Bearer <token>.
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | What the widget is for, 1 to 100 characters. |
hostnames |
array of string | yes | The hostnames the widget works on, such as example.com. A hostname also covers every name under it, so example.com covers www.example.com. |
mode |
string | no | managed, non_interactive or invisible. |
appearance |
object or null | no | Any of theme (auto, light, dark), size (normal, flexible, compact) and language (auto or a code such as "es"). |
branded |
boolean | no | Show Wicket's name on the widget. Turning it off needs a plan that includes widgets without Wicket's name. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
201 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Fields of a 201 response:
| Field | Type | Description |
|---|---|---|
widget |
WidgetDetail | |
widget.id |
integer | |
widget.name |
string | |
widget.site_key |
string | The public key your page puts in the widget. It starts with wk_. |
widget.mode |
string | managed, non_interactive or invisible. |
widget.status |
string | active, or disabled when our team turned the widget off. |
widget.branded |
boolean | Whether you chose to show Wicket's name on the widget. |
widget.hostnames |
array of string | Every hostname the widget lists. |
widget.hostname_count |
integer | |
widget.created_at |
string | |
widget.last_challenge_at |
string or null | When the widget last started a challenge, to the minute. |
widget.stats_24h |
Stats24h | |
widget.attention |
array of string | Why the widget needs a look, if it does: disabled (our team turned it off), not_verifying (20 or more passes in 24 hours and your server verified none) or hostname_refused (a challenge came from a page whose hostname the widget does not list). |
widget.disabled_reason |
string or null | Why our team turned the widget off, or null when it is not turned off. |
widget.appearance |
Appearance | The theme, size and language the widget uses when the page sets none. |
widget.secret_prefix |
string | The start of the secret key, to tell keys apart. The rest is never shown again. |
widget.secret_rotated_at |
string or null | |
widget.previous_secret_expires_at |
string or null | When the secret key you replaced stops working, while a rotation's grace period is running. |
widget.limits |
Limits | What your plan allows: {"hostnames": 10} is the most hostnames one widget lists. |
widget.embed |
Embed | |
secret |
string | The secret key. It is shown once, so save it now. |
Get widget
Section titled Get widgetGET /api/v1/client/wicket/widgets/{widget_id}
Read one widget: every hostname, its appearance, the start of its secret key, your plan's hostname limit and the script and verify addresses to use.
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
widget_id |
path | integer | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Fields of a 200 response:
| Field | Type | Description |
|---|---|---|
id |
integer | |
name |
string | |
site_key |
string | The public key your page puts in the widget. It starts with wk_. |
mode |
string | managed, non_interactive or invisible. |
status |
string | active, or disabled when our team turned the widget off. |
branded |
boolean | Whether you chose to show Wicket's name on the widget. |
hostnames |
array of string | Every hostname the widget lists. |
hostname_count |
integer | |
created_at |
string | |
last_challenge_at |
string or null | When the widget last started a challenge, to the minute. |
stats_24h |
Stats24h | |
stats_24h.issued |
integer | Challenges Wicket started for the widget in the last 24 hours. |
stats_24h.passed |
integer | Challenges a visitor passed in the last 24 hours. |
stats_24h.failed |
integer | Challenges a visitor failed in the last 24 hours. |
stats_24h.solve_rate |
number or null | passed divided by issued, or null when nothing was issued. |
attention |
array of string | Why the widget needs a look, if it does: disabled (our team turned it off), not_verifying (20 or more passes in 24 hours and your server verified none) or hostname_refused (a challenge came from a page whose hostname the widget does not list). |
disabled_reason |
string or null | Why our team turned the widget off, or null when it is not turned off. |
appearance |
Appearance | The theme, size and language the widget uses when the page sets none. |
secret_prefix |
string | The start of the secret key, to tell keys apart. The rest is never shown again. |
secret_rotated_at |
string or null | |
previous_secret_expires_at |
string or null | When the secret key you replaced stops working, while a rotation's grace period is running. |
limits |
Limits | What your plan allows: {"hostnames": 10} is the most hostnames one widget lists. |
embed |
Embed | |
embed.script_url |
string or null | The script your page loads. |
embed.siteverify_url |
string | The address your server posts the token and the secret key to. |
Change a widget's name, hostnames, mode, appearance or branding
Section titled Change a widget's name, hostnames, mode, appearance or brandingPATCH /api/v1/client/wicket/widgets/{widget_id}
Change a widget's name, hostnames, mode, appearance or branding. Send only what changes; hostnames is the complete new list.
Answers 402 when the new hostnames pass your plan's limit for one widget, or when you turn Wicket's name off on a plan that does not include it. Answers 422 for a value Wicket refuses, and the message names it.
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
widget_id |
path | integer | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
name |
string or null | no | The new name, 1 to 100 characters. |
hostnames |
array of string or null | no | The complete list of hostnames. It replaces the current list. |
mode |
string or null | no | managed, non_interactive or invisible. |
appearance |
object or null | no | Any of theme, size and language. A setting you leave out keeps its value. |
branded |
boolean or null | no | Show Wicket's name on the widget. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Fields of a 200 response:
| Field | Type | Description |
|---|---|---|
id |
integer | |
name |
string | |
site_key |
string | The public key your page puts in the widget. It starts with wk_. |
mode |
string | managed, non_interactive or invisible. |
status |
string | active, or disabled when our team turned the widget off. |
branded |
boolean | Whether you chose to show Wicket's name on the widget. |
hostnames |
array of string | Every hostname the widget lists. |
hostname_count |
integer | |
created_at |
string | |
last_challenge_at |
string or null | When the widget last started a challenge, to the minute. |
stats_24h |
Stats24h | |
stats_24h.issued |
integer | Challenges Wicket started for the widget in the last 24 hours. |
stats_24h.passed |
integer | Challenges a visitor passed in the last 24 hours. |
stats_24h.failed |
integer | Challenges a visitor failed in the last 24 hours. |
stats_24h.solve_rate |
number or null | passed divided by issued, or null when nothing was issued. |
attention |
array of string | Why the widget needs a look, if it does: disabled (our team turned it off), not_verifying (20 or more passes in 24 hours and your server verified none) or hostname_refused (a challenge came from a page whose hostname the widget does not list). |
disabled_reason |
string or null | Why our team turned the widget off, or null when it is not turned off. |
appearance |
Appearance | The theme, size and language the widget uses when the page sets none. |
secret_prefix |
string | The start of the secret key, to tell keys apart. The rest is never shown again. |
secret_rotated_at |
string or null | |
previous_secret_expires_at |
string or null | When the secret key you replaced stops working, while a rotation's grace period is running. |
limits |
Limits | What your plan allows: {"hostnames": 10} is the most hostnames one widget lists. |
embed |
Embed | |
embed.script_url |
string or null | The script your page loads. |
embed.siteverify_url |
string | The address your server posts the token and the secret key to. |
Delete a widget
Section titled Delete a widgetDELETE /api/v1/client/wicket/widgets/{widget_id}
Delete a widget. Its site key and secret key stop working at once, so a form that uses the widget stops passing.
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
widget_id |
path | integer | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Fields of a 200 response:
| Field | Type |
|---|---|
status |
string |
Widget analytics
Section titled Widget analyticsGET /api/v1/client/wicket/widgets/{widget_id}/analytics
The numbers of one widget over a range: a point for each hour when the numbers cover 7 days or less, or for each day when they cover more, the totals with how many tokens your server verified, and the top ten hostnames, actions, countries, browsers and operating systems.
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
widget_id |
path | integer | yes | |
range |
query | string | no | How far back to read: 24h (the default), 7d, 30d, 90d or 365d. A range longer than your plan reads back is not refused: the answer covers the days your plan allows, says clamped is true and names the plan that allows the range in upgrade. Any other word answers 422. Default: 24h. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Fields of a 200 response:
| Field | Type | Description |
|---|---|---|
range |
string | The range you asked for. |
from |
string | The start of the span the numbers cover. |
to |
string | |
granularity |
string | hour when the numbers cover 7 days or less, day when they cover more (30, 90 and 365 days). |
allowed_days |
integer | How many days back your plan reads. |
clamped |
boolean | True when the range is longer than your plan allows, so the numbers cover allowed_days only. |
upgrade |
Upgrade or null | Set when clamped: the plan that allows the range you asked for. |
upgrade.plan |
string or null | The plan that allows the range you asked for, such as plan-pro. |
series |
array of SeriesPoint | |
series[].t |
string | |
series[].issued |
integer | |
series[].passed |
integer | |
series[].passed_interactive |
integer | |
series[].failed |
integer | |
series[].interactive_shown |
integer | |
totals |
AnalyticsTotals | |
totals.issued |
integer | |
totals.passed |
integer | |
totals.passed_interactive |
integer | |
totals.failed |
integer | |
totals.interactive_shown |
integer | |
totals.unsolved |
integer | issued minus passed minus failed: challenges nobody finished. |
totals.solve_rate |
number or null | |
totals.verify |
VerifyTotals | |
top |
AnalyticsTop | |
top.hostname |
array of TopRow | |
top.action |
array of TopRow | |
top.country |
array of TopRow | |
top.browser |
array of TopRow | |
top.os |
array of TopRow |
Make a new secret key for a widget
Section titled Make a new secret key for a widgetPOST /api/v1/client/wicket/widgets/{widget_id}/secret
Make a new secret key for a widget. The answer holds it once, so save it now.
With grace set to 2h the old secret key keeps working for 2 hours, so you can change your server without a gap. With none it stops at once. Any other value answers 422. We email the account owner when a secret key is rotated.
Authentication: an access token, sent as Authorization: Bearer <token>.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
widget_id |
path | integer | yes |
Request body
Section titled Request bodyapplication/json
| Field | Type | Required | Description |
|---|---|---|---|
grace |
string | no | 2h keeps the old secret key working for 2 hours. none stops it at once. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Fields of a 200 response:
| Field | Type | Description |
|---|---|---|
widget |
WidgetDetail | |
widget.id |
integer | |
widget.name |
string | |
widget.site_key |
string | The public key your page puts in the widget. It starts with wk_. |
widget.mode |
string | managed, non_interactive or invisible. |
widget.status |
string | active, or disabled when our team turned the widget off. |
widget.branded |
boolean | Whether you chose to show Wicket's name on the widget. |
widget.hostnames |
array of string | Every hostname the widget lists. |
widget.hostname_count |
integer | |
widget.created_at |
string | |
widget.last_challenge_at |
string or null | When the widget last started a challenge, to the minute. |
widget.stats_24h |
Stats24h | |
widget.attention |
array of string | Why the widget needs a look, if it does: disabled (our team turned it off), not_verifying (20 or more passes in 24 hours and your server verified none) or hostname_refused (a challenge came from a page whose hostname the widget does not list). |
widget.disabled_reason |
string or null | Why our team turned the widget off, or null when it is not turned off. |
widget.appearance |
Appearance | The theme, size and language the widget uses when the page sets none. |
widget.secret_prefix |
string | The start of the secret key, to tell keys apart. The rest is never shown again. |
widget.secret_rotated_at |
string or null | |
widget.previous_secret_expires_at |
string or null | When the secret key you replaced stops working, while a rotation's grace period is running. |
widget.limits |
Limits | What your plan allows: {"hostnames": 10} is the most hostnames one widget lists. |
widget.embed |
Embed | |
secret |
string | The secret key. It is shown once, so save it now. |
Tell Wicket what a passed check turned out to be
Section titled Tell Wicket what a passed check turned out to bePOST /api/v1/wicket/feedback
Tell Wicket what a passed check turned out to be.
When you learn that an account or an order your form made was a bot, or
was a person Wicket doubted, post the check's event (from
metadata.event in the siteverify answer), with your widget's secret
key and a label of bot or human. Our team and the model that scores
checks learn from your report. The answer is 202 and the report starts
as confirmed.
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
secret |
string | yes | The widget's secret key, which starts with wks_. |
event |
string | yes | The check's id, from metadata.event in the siteverify answer. 32 hex characters. |
label |
string | yes | What the visitor turned out to be: "bot" or "human". |
note |
string or null | no | A short note for our team, at most 500 characters. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
202 |
Success. |
403 |
The secret key is not a widget's. The answer names the error invalid_secret. |
422 |
The event is not a check of this widget, or the label is not bot or human. |
429 |
The widget used its budget of calls for the minute. |
Fields of a 202 response:
| Field | Type | Description |
|---|---|---|
status |
string | Always "received". |
Check a token the widget put in your form
Section titled Check a token the widget put in your formPOST /api/v1/wicket/siteverify
Check a token the widget put in your form.
Post the widget's secret key and the token (response) from your
server, form-encoded, as multipart form data or as JSON, as you would to
Cloudflare Turnstile. The answer is always HTTP 200 with success true or
false and an error-codes list, except when the widget has used its
budget of calls for the minute (6000 by default), which is HTTP 429 with
the code rate-limited.
A token passes once: a second call with the same token answers
timeout-or-duplicate, unless you send the same idempotency_key, which
returns the first answer again. A token is also timeout-or-duplicate
when it is more than 300 seconds old. On success, check that hostname
is your own and, if you set one on the widget, that action is the one
you expect. metadata.event is the check's id, for the feedback call.
The test secret keys wks_test_pass, wks_test_fail and wks_test_spent
answer a fixed result for any token and count nowhere.
Request body
Section titled Request bodyapplication/x-www-form-urlencoded (required)
| Field | Type | Required | Description |
|---|---|---|---|
secret |
string | yes | The widget's secret key, which starts with wks_. Keep it on your server. |
response |
string | yes | The token the widget put in your form, from the field named wicket-response. At most 2048 characters. |
remoteip |
string or null | no | The visitor's IP address as your server sees it. Wicket notes whether it comes from the same network that solved the check. It never changes the answer. |
idempotency_key |
string or null | no | A value you choose for this verification, such as a UUID. If you send the same token again with the same key, you get the first answer again instead of timeout-or-duplicate. Use it when a network error makes you repeat a call. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
429 |
The widget used its budget of siteverify calls for the minute (error code rate-limited). |
Fields of a 200 response:
| Field | Type | Description |
|---|---|---|
success |
boolean | True when the token is valid for this widget and had not been used. |
challenge_ts |
string or null | When the visitor passed the check, in UTC. |
hostname |
string or null | The hostname of the page that showed the widget. Compare it with your own. |
error-codes |
array of string | Why the call failed, empty when it succeeded. One or more of: missing-input-secret, invalid-input-secret, missing-input-response, invalid-input-response, bad-request, timeout-or-duplicate, internal-error and rate-limited. |
action |
string or null | The action the page set on the widget, or an empty string. |
cdata |
string or null | The cdata the page set on the widget, or an empty string. |
metadata |
SiteverifyMetadata or null | More about the check, on success. |
metadata.interactive |
boolean | True when the visitor ticked the checkbox to pass. |
metadata.event |
string | The id of this check, 32 hex characters. Store it with the record the form made (an account, an order) to report later, with the feedback call, whether that record was a person or a bot. |