API reference
Sites
Management endpoints for sites: create, read, update allowed origins, rotate site keys and delete.
Base URL https://imnotahuman.ai/api/v1. Request bodies must be JSON with Content-Type: application/json (else 415) and at most 32,000 bytes. Bodies are validated strictly: unknown fields fail with VALIDATION_FAILED. Every response carries X-Request-Id (echoing yours if you send one) and Cache-Control: no-store except JWKS. Errors are { "error": { "code", "message", "details"? } }; see Errors.
Management endpoints require Authorization: Bearer <access token> where the token is the Supabase Auth access token from an email-and-password dashboard session. It is validated on every request, so signing out revokes access immediately. Missing header: AUTHENTICATION_REQUIRED (401); invalid or expired: INVALID_SESSION (401). Resources you do not own return NOT_FOUND. Rate limits: 600/min per network, 300/min per user.
List and create sites
curl -X POST https://imnotahuman.ai/api/v1/sites \
-H 'authorization: Bearer <token>' -H 'content-type: application/json' \
-d '{"name":"Example Shop","domain":"example.com","allowed_origins":["http://localhost:5173"]}'| Field | Type | Description |
|---|---|---|
namerequired | string 1–80 | Display name. |
domainrequired | hostname | Lowercase hostname, e.g. example.com. Scheme and path are stripped; must contain a dot unless localhost. |
allowed_origins | string[] ≤ 20 | Extra origins (scheme://host[:port]) allowed to create challenges, in addition to https://<domain> and subdomains. |
{
"site": {
"id": "site_c4n7xq2mfb3ktw6y",
"name": "Example Shop",
"domain": "example.com",
"public_site_key": "site_live_exampleweb2ab3cd4ef5gh6j",
"test_site_key": "site_test_exampleweb2ab3cd4ef5gh6j",
"status": "active",
"allowed_origins": ["http://localhost:5173"],
"created_at": "2026-09-20T11:40:00.000Z",
"updated_at": "2026-09-20T11:40:00.000Z"
}
}Limit 25 sites per account (CONFLICT beyond). Invalid domain or origin values return VALIDATION_FAILED with details.issues. GET returns { "sites": [...] }.
Read, update, delete
# { "site", "recent": [25 events] }
curl https://imnotahuman.ai/api/v1/sites/site_c4n7xq2mfb3ktw6y -H 'authorization: Bearer <token>'
curl -X PATCH https://imnotahuman.ai/api/v1/sites/site_c4n7xq2mfb3ktw6y \
-H 'authorization: Bearer <token>' -H 'content-type: application/json' \
-d '{"allowed_origins":["http://localhost:5173","https://staging.example.net"],"status":"active"}'
curl -X DELETE https://imnotahuman.ai/api/v1/sites/site_c4n7xq2mfb3ktw6y -H 'authorization: Bearer <token>'
# { "deleted": true }PATCH accepts name, status (active | disabled) and allowed_origins (replaces the whole list). A disabled site rejects challenge creation with SITE_DISABLED.
Rotate site keys
curl -X POST https://imnotahuman.ai/api/v1/sites/site_c4n7xq2mfb3ktw6y/rotate-keys -H 'authorization: Bearer <token>'
# { "site": { ..., "public_site_key": "site_live_<new>", "test_site_key": "site_test_<new>" } }Both keys are replaced immediately; the old keys stop creating challenges. Update embeds first.