[ developers ]

One script. One GET.

Embed the collector, then read the verdict from your backend before any expensive action. Shadow mode first; enforcement when you trust it. See it live.

Scripts and browser automation can leave adverse signals, while coherent cold bots remain a known limitation.

1 · embed + csp
<script src="https://humanproof.work/gate.js"
        data-site-key="hpv_..." async></script>

# csp allowance
Content-Security-Policy:
  script-src 'self' https://humanproof.work;
  connect-src 'self' https://humanproof.work
2 · read the standing
curl "https://humanproof.work/api/verify/standing?sessionToken=hpv_st_..." \
  -H "Authorization: Bearer hpv_sk_..."

# { "score": 91, "tier": "passive", "label": "Likely human",
#   "pass": true, "confidence": "medium",
#   "reasons": ["human_evidence_observed"] }
3 · evaluate an action (typescript)
import { HumanProofClient, createActionId } from "@humanproof/server";

const hp = new HumanProofClient({ secret: process.env.HUMANPROOF_SECRET! });
const result = await hp.evaluate({
  actionId: createActionId(), sessionToken, action: "ai_credits"
});
4 · report the outcome (calibration)
curl -X POST https://humanproof.work/api/abuse/outcome \
  -H "Authorization: Bearer hpv_sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "outcomeId": "result-123", "actionId": "generation-123",
        "outcome": "abuse", "confirmedLossUsdMicros": 25000 }'

[ keys ]

A public hpv_… site key binds the collector to your allow-listed origins; the matching secret hpv_sk_… reads the verdict server-side. Create your own in the dashboard (sign in, add your origins, copy the keys) — or try hpv_internal on this domain. Base URL https://humanproof.work. The versioned server contract is available as OpenAPI v1.

[ onboarding ]

A new account can complete the full activation path in the dashboard: create an app, register exact origins, store the one-time server secret, install the collector, obtain a proof, configure the webhook endpoint, run one shadow evaluation, accept its signed delivery, and submit an independent outcome. Progress is resumable and diagnostics contain only safe integration facts.

customer csp
# Use your deployed HumanProof base URL
Content-Security-Policy: script-src 'self' https://humanproof.work; connect-src 'self' https://humanproof.work

# An origin is scheme + host + optional port, with no path or wildcard
https://app.example.com
http://localhost:3000
  • invalid_site_key: copy the active public hpv_ key; never use hpv_sk_ in a browser.
  • origin_not_allowed: make the dashboard origin exactly match the browser scheme, host, and port.
  • Missing coherence: deploy the current /gate.js or current collector package instead of a cached legacy build.
  • Webhook signature failures: verify the exact raw body and keep the receiver clock synchronized within five minutes.
  • Missing outcomes: submit a closed customer outcome with the original actionId; it never rewrites or retrains the recommendation.

[ server_sdks ]

The TypeScript and Python clients provide typed proof, evaluation, and outcome calls, bounded timeouts and safe retries, explicit outage fallback, idempotency helpers, and exact-body webhook verification. Keep the hpv_sk_… secret on your server.

typescript · server code only
import { HumanProofClient, createActionId } from "@humanproof/server";

const hp = new HumanProofClient({ secret: process.env.HUMANPROOF_SECRET! });
const result = await hp.evaluate({
  actionId: createActionId(), sessionToken, action: "ai_credits"
});
python · server code only
import os
from humanproof import HumanProofClient, create_action_id

hp = HumanProofClient(os.environ["HUMANPROOF_SECRET"])
result = hp.evaluate({
    "actionId": create_action_id(), "sessionToken": session_token,
    "action": "ai_credits",
})

[ test_mode ]

The repository includes a bounded in-memory simulator with visibly synthetic fixtures for strong human evidence, insufficient evidence, obvious automation, velocity, retry, outage fallback, and signed webhooks. It has no production database path, so its actions never enter reputation, reporting, quota, calibration, or billing. The maintained Next.js 16 reference covers collector token handoff through outcomes and exact-body webhook verification.

[ endpoints ]

SCRIPT/gate.jsthe passive collector — one tag, no UI
GET/api/verify/standingread the durable session standing
POST/api/verifyone-shot verification of a session token
POST/api/abuse/evaluateidempotent recommendation before an expensive action
POST/api/abuse/outcomereport what actually happened — feeds calibration

EMBED site key + script

One script tag; it runs ambiently on the whole page and accumulates a standing verdict bound to an opaque, app-scoped session token. (Field mode still works for a one-shot token — add data-humanproof-gate to a field.)
embed
<script src="https://humanproof.work/gate.js" data-site-key="hpv_..." async></script>
token handoff
window.addEventListener("humanproof:token", (event) => {
  sendToYourServer(event.detail.sessionToken);
});

GET /api/verify/standing

The headline read: your server fetches the session's standing verdict with its secret key — challenge-free, no token consumed, read it as often as you like. Once a device has been seen acting human it holds a durable pass through idle; only a fresh automated signal revokes it, and a never-proven device reads insufficient.
curl
curl "https://humanproof.work/api/verify/standing?sessionToken=hpv_st_..." \
  -H "Authorization: Bearer hpv_sk_..."

# { "score": 91, "tier": "passive", "label": "Likely human",
#   "pass": true, "confidence": "medium", "reasons": ["human_evidence_observed"],
#   "input_authenticity": { "score": 84, "confidence": "high" } }

Gate on pass + tier. The live ceiling is Likely human, never guaranteed identity or personhood. The compatibility-only input_authenticity field and legacy deviceToken query alias remain during the measured migration window and do not affect the pass. Session tokens expire after 24 hours and rotate under a versioned key ring. The response carries no internal feature names or weights, and typed content is never collected.

POST /api/verify

One-shot alternative: exchange a single-use collect token for the same decision. Single-use, and the score is advisory — it supports a decision, it does not make one.
curl
curl -X POST https://humanproof.work/api/verify \
  -H "Authorization: Bearer hpv_sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "token": "hpv_tok_..." }'

# { "human": { "score": 89, "tier": "passive", "label": "Likely human",
#                "pass": true, "confidence": "medium", "reasons": ["human_evidence_observed"] },
#   "flags": [], "stats": { ... } }

POST /api/abuse/evaluate

Evaluate one protected action from your server. The unique action ID is app-scoped: an identical retry returns the original recommendation without adding velocity, while conflicting reuse returns 409. New apps start in shadow, so the recommendation remains visible without silently becoming customer enforcement.
curl
curl -X POST https://humanproof.work/api/abuse/evaluate \
  -H "Authorization: Bearer hpv_sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "actionId": "generation-123", "sessionToken": "hpv_st_...", "action": "ai_credits" }'

# { "decision": "allow", "confidence": "medium", "reasons": [],
#   "policyVersion": "ai_credits-2026-07-22", "mode": "shadow", "proof": { ... } }

POST /api/abuse/outcome

Attach independent customer truth to the original app-scoped action ID. Outcome IDs make retries exact; a correction supplies a new outcome ID and names the current outcome it corrects. History is append-only and never rewrites the HumanProof recommendation or its policy version.
curl
curl -X POST https://humanproof.work/api/abuse/outcome \
  -H "Authorization: Bearer hpv_sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "outcomeId": "result-123", "actionId": "generation-123",
        "outcome": "abuse", "occurredAt": "2026-07-22T16:00:00.000Z",
        "confirmedLossUsdMicros": 25000 }'

# { "outcomeId": "result-123", "actionId": "generation-123",
#   "outcome": "abuse", "source": "customer_api", "occurredAt": "...",
#   "receivedAt": "...", "confirmedLossUsdMicros": 25000 }

[ what_is_live ]

Collection, one-shot proof, standing reads, app-scoped reputation, guided self-serve onboarding, idempotent shadow action recommendations, independent outcomes, signed webhooks, OpenAPI, and TypeScript and Python server SDK packages, an isolated synthetic simulator, and a maintained Next.js reference, authenticated application shell, evaluation explorer, self-serve policy controls, and exact source-backed usage with customer caps are implemented. Subscription billing is not available yet. Launch is planned at $499/month for one app and 100,000 evaluated actions.

[ errors ]

401invalid_keyinvalid or missing secret key — rotate in the dashboard
403origin_not_allowedcollector origin off the exact allow-list — add scheme + host + port
400invalid_tokeninvalid or already-used token — mint a fresh single-use collect token
429rate_limitedper-app quota exceeded — backs off with retry-after
409idempotency_conflictaction ID reused with a conflicting payload — mint a new action ID
503outage_fallbacktemporary outage — apply the configured allow | limit | step_up fallback

Errors return a stable safe code, for example { "error": "…", "code": "rate_limited" }. Evaluation outages also carry the configured allow | limit | step_up fallback; SDK errors never include secrets or request bodies.

keys live in the dashboard under integration · secret keys reveal once, rotate any time. create one in your dashboard — or try hpv_internal on this domain.