HomeDocs

API Reference

All endpoints live under the base URL:

https://verify.nexlolabs.net/api

All requests and responses are JSON. Errors follow the shape described under Error codes.

Public endpoints

These endpoints are called by the widget or your backend. They do not require a session.

Create a challenge

POST /api/challenge/create

Creates a new challenge for the given site key.

{
  "siteKey": "nlx_site_YOUR_SITE_KEY",
  "type": "checkbox",
  "difficulty": "normal",
  "theme": "auto"
}
FieldTypeRequiredDescription
siteKeystringyesPublic site key.
typestringnocheckbox, image_select, puzzle, math, code, shapes, vowels, invisible. Default checkbox.
difficultystringnoeasy, normal, hard. Falls back to the site default.
themestringnoauto, light, dark.

Response 200:

{
  "success": true,
  "challengeId": "clx9abc123",
  "type": "image_select",
  "expires": "2026-08-06T12:00:00.000Z",
  "data": { "target": "A", "tiles": [...] }
}

Solve a challenge

POST /api/challenge/solve

Submits the answer and, on success, returns a signed token.

{
  "challengeId": "clx9abc123",
  "answer": "A,B,C",
  "behavior": { "elapsedMs": 4321, "moveCount": 47, "mouseEntropy": 0.83 }
}
FieldTypeRequiredDescription
challengeIdstringyesFrom create.
answerstringyesThe user's answer.
behaviorobjectnoBehavioral snapshot.

Response 200:

{
  "success": true,
  "token": "v1.eyJ...sig",
  "expires": "2026-08-06T12:02:00.000Z"
}

A challenge allows 3 attempts before it is marked failed.

Verify a token (server-side)

POST /api/challenge/verify

Exchange a token for the verification result. Use your site secret here — never in the browser.

{
  "token": "v1.eyJ...",
  "secret": "nlx_secret_YOUR_SITE_SECRET"
}
FieldTypeRequiredDescription
tokenstringyesToken from solve.
secretstringyesSite secret (backend only).

Response 200:

{
  "success": true,
  "score": 0.97,
  "challengeId": "clx9abc123",
  "hostname": "example.com",
  "expires": "2026-08-06T12:02:00.000Z"
}
FieldDescription
successtrue when token is valid, unused, unexpired.
scoreRisk score 0 (bot) – 1 (human).
challengeIdThe challenge that produced the token.
hostnameThe origin the widget ran on (already whitelist-checked).
expiresToken expiry timestamp.

Health

GET /api/health

Returns { status: "ok", uptime, version, checks: { database, redis } }. A liveness-only variant GET /api/health/live always returns 200 once the process is up.

Authenticated endpoints (dashboard session)

All of the following require your dashboard session cookie. The browser automatically sends the CSRF token (X-CSRF-Token, obtained from GET /api/auth/csrf).

Auth

MethodPathDescription
POST/api/auth/registerCreate an account (email, password).
POST/api/auth/loginLogin (email, password). Returns requiresTwoFactor if 2FA is on.
POST/api/auth/2fa/verifyComplete login with a TOTP code.
POST/api/auth/refreshRefresh the session.
POST/api/auth/logoutEnd the session.
GET/api/auth/csrfGet the CSRF token.
POST/api/auth/password/reset-requestRequest a password reset.
POST/api/auth/password/resetSet a new password with the reset token.
GET/api/auth/meCurrent user.
PATCH/api/auth/profileUpdate profile.
PATCH/api/auth/passwordChange password (requires current password).
GET/api/auth/2fa/setupStart 2FA setup; returns a TOTP secret + otpauth URL.
POST/api/auth/2fa/enableEnable 2FA (verify a code first).
POST/api/auth/2fa/disableDisable 2FA.

Sites

MethodPathDescription
POST/api/site/createCreate a site (returns siteKey, siteSecret once).
POST/api/site/deleteDelete a site.
GET/api/site/listList your sites.
POST/api/site/domainsRegister a domain for a site.
DELETE/api/site/domainsRemove a domain.
POST/api/site/secret/rotateRotate a site secret.

API keys

API keys (nlx_live_...) can be used instead of a session for the read endpoints. Auth via Authorization: Bearer nlx_live_....

ScopeEndpoints
statistics:readGET /api/statistics
verifications:readGET /api/verifications
MethodPathDescription
GET/api/keysList your API keys (never the full key).
POST/api/keysCreate an API key ({ name, scopes }); the key value is shown once.
POST/api/keys/deleteRevoke an API key.

Statistics

MethodPathDescription
GET/api/statisticsAggregated stats (?range=day|week|month|all, ?siteId=).
GET/api/verificationsRecent verification history (?limit=, ?offset=).

Admin endpoints

Prefix /api/admin. Requires the ADMIN role. Accessible surface:

  • GET /api/admin/overview — platform stats, top sites, recent verifications.
  • User management: GET/PATCH/DELETE /api/admin/users.
  • Site management: GET/DELETE /api/admin/sites, POST /api/admin/sites/:id/suspend.
  • Domain blocklist: GET /api/admin/domains/blocked, POST /api/admin/domains/block, DELETE /api/admin/domains/block.
  • Key blocklist: GET /api/admin/keys/blocked, POST /api/admin/keys/block, DELETE /api/admin/keys/block.
  • API-key management: GET/DELETE /api/admin/api-keys.
  • Challenges: GET /api/admin/challenges, POST /api/admin/challenges/:id/revoke.
  • CSV export: GET /api/admin/export/verifications — downloads verification data as a verifications.csv attachment (content-disposition).
  • Logs: GET /api/admin/logs.
  • Maintenance: POST /api/admin/challenges/expire-stale.

Rate limits

RouteLimitWindow
/api/auth/*10 requests/ip15 min
/api/challenge/create30/ip/device60 s
/api/challenge/solve60/ip60 s
/api/challenge/verify120/ip/secret60 s

Exceeding a limit returns 429 with code RATE_LIMITED.