v1.0

Integrate AmHuman

Add human verification to your site in under 5 minutes. One component, zero backend required.

Quick Start

Four steps to verify humans on your site. No backend code needed for most use cases.

1

Get your frontend key

Sign up at /vendor/login and copy your Frontend key from the dashboard. This key is safe to use in client-side code.

text
iah_pk_a1b2c3d4e5f6...
2

Install the SDK

Pick your framework and install the package. Using plain HTML? Skip this step — just add a script tag.

npm install @amhumanorg/react
3

Add the widget to your page

Drop in the component wherever you want the verification step — checkout, signup, or any protected action.

import { AmHumanVerify } from '@amhumanorg/react';

function Checkout() {
  const [verified, setVerified] = useState(false);

  return (
    <form onSubmit={handleSubmit}>
      {/* ... your form fields ... */}

      <AmHumanVerify
        clientKey="iah_pk_..."
        purpose="Complete purchase"
        onVerified={() => setVerified(true)}
      />

      <button type="submit" disabled={!verified}>
        Place Order
      </button>
    </form>
  );
}
4

Whitelist your domain

In your dashboard, add your site's domain under Allowed Domains. The widget will only load on whitelisted domains.

text
yourdomain.com
staging.yourdomain.com
localhost  ← works automatically for dev

That's it for most use cases

If you're using AmHuman for bot prevention, signup gating, or spam reduction, you're done. No backend code needed. The widget handles everything.

Need stronger guarantees for payments or high-value actions? Add backend validation — it's one API call.

Installation

Packages are published on the public npm registry (@amhumanorg/*). Choose your framework — all wrap the same widget.

npm install @amhumanorg/react

No framework?

The vanilla HTML script tag works everywhere — WordPress, Shopify, static sites, or any page that runs JavaScript. No build step required.

Add the Widget

The widget renders a self-contained verification UI inside your page. The user types their AmHuman handle, approves on their device, and your callback fires. You don't need to manage any of the verification logic.

What the user sees

Verify you're human

@ enter your handle
Verify

Don't have one? Create yours

powered by AmHuman

Props / Options

PropTypeRequiredDescription
clientKeystringYesYour publishable frontend key (iah_pk_...)
purposestringNoShown to the user during approval (e.g. "Complete purchase")
containerstringHTML onlyCSS selector for the container element (vanilla JS only)
onVerifiedfunctionYesCalled when the user approves. Receives { token }
onDeniedfunctionNoCalled when the user denies the request
onExpiredfunctionNoCalled when the request times out
onErrorfunctionNoCalled on errors. Receives { error }
onReadyfunctionNoCalled when the widget iframe has loaded

Callbacks

The widget communicates results through callbacks. At minimum, handle onVerified.

CallbackPayloadWhen
onVerified{ requestId, token?, type, … }User approved — token is present for Tier 2 backend validation
onDenied{ }User explicitly denied
onExpired{ }Request timed out before response
onError{ error }Network error, invalid key, handle not found
onReady{ }Widget loaded and visible

postMessage protocol

Under the hood, all callbacks use postMessage between the iframe and your page. If you prefer low-level control (e.g. for Web Workers or non-DOM environments), listen for message events prefixed with amhuman: — e.g. amhuman:verified, amhuman:denied.

Backend Validation

Optional — for high-stakes flows

For payments, limited inventory, or anything where a forged verification has real consequences, validate the token on your server before proceeding. This prevents users from faking the onVerified callback in dev tools.

When do you need this?

You need backend validation if a fake verification would cost you money or create abuse — ticket purchases, one-per-person promos, financial transactions.

You don't need it if you're just blocking bots — signup gating, spam prevention, content access. A bot can't fake the widget interaction, and a real human bypassing it in dev tools is... a real human.

Step 1: Pass the token to your backend

The onVerified callback includes a result.token — a one-time cryptographic proof. Send it to your server alongside your form data.

import { AmHumanVerify } from '@amhumanorg/react';

function Checkout({ orderData }) {
  async function handleVerified(result) {
    // Pass the token to your backend alongside order data
    const res = await fetch('/api/place-order', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        ...orderData,
        humanToken: result.token,
      }),
    });
    // ...
  }

  return (
    <AmHumanVerify
      clientKey="iah_pk_..."
      purpose="Purchase: 2x concert tickets"
      onVerified={handleVerified}
    />
  );
}

Step 2: Validate on your server

POST /api/verify/validate on your API host with your secret key in the X-API-Key header (same key as the vendor dashboard). Example base URL: https://amhuman-api.onrender.com — set NEXT_PUBLIC_API_URL in the web app to match. The token is single-use and expires after 5 minutes.

// In your order/checkout endpoint — use your API origin + POST /api/verify/validate
// Example origin: https://amhuman-api.onrender.com
app.post('/api/place-order', async (req, res) => {
  const { humanToken, ...orderData } = req.body;

  const verify = await fetch('https://amhuman-api.onrender.com/api/verify/validate', {
    method: 'POST',
    headers: {
      'X-API-Key': 'iah_sk_...',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ token: humanToken }),
  });

  const body = await verify.json();
  const valid = body?.data?.valid;

  if (!valid) {
    return res.status(403).json({ error: 'Human verification failed' });
  }

  await processOrder(orderData);
});

Validation response

FieldTypeDescription
successbooleanAlways true when HTTP 200
data.validbooleanWhether the token is valid (single-use)
data.handlestringThe verified user's handle when valid is true
data.purposestring | nullThe purpose string from the original request
data.verifiedAtstringISO 8601 timestamp of when the user approved
data.verificationLevelstringping | biometric | full

Test Mode

Use your test frontend key (iah_pk_test_...) to test the full flow without real users. The widget works identically but uses reserved test handles that auto-respond.

javascript
AmHuman.verify({
  clientKey: 'iah_pk_test_...',   // Use your test key from the dashboard
  purpose: 'Test checkout',
  container: '#amhuman',
  onVerified: function(result) {
    console.log('Verified!', result);
    // result.token — validate server-side with POST /api/verify/validate + X-API-Key
  },
});

// Reserved test handles (type in the widget):
//   test_approve  → auto-confirms after ~2 seconds
//   test_deny     → auto-denies after ~2 seconds
//   test_expire   → never responds (times out)

Test handles

HandleBehaviorUse case
test_approveAuto-confirms after ~2 secondsTest the happy path
test_denyAuto-denies after ~2 secondsTest denial handling
test_expireNever responds (times out)Test timeout/expiry UI

Test tokens validate too

Tokens from test mode work with the same POST /api/verify/validate call and X-API-Key as production. Use your test publishable key in the widget and your secret key on the server.

Verification Levels

Choose how much proof you need. Set a default in your dashboard, or override per-request.

Ping90 secondsDefault

User receives a notification and taps Approve or Deny. Lowest friction.

Best for: login confirmations, age gates, comment posting, low-value actions

Biometric300 seconds

Live face + voice + palm challenge. Biometric data stays on AmHuman's infrastructure — never touches yours.

Best for: financial transactions, ticket purchases, account recovery

Full600 seconds

Complete multi-modal liveness test with device attestation. Equivalent to initial enrollment.

Best for: regulated industries, high-value transactions, identity binding

Webhooks

Optional — for server-to-server flows

Instead of (or in addition to) widget callbacks, receive real-time HTTP notifications on your server when a verification completes. Configure your webhook URL in the dashboard.

Payload

json
{
  "event": "verification.completed",
  "requestId": "req_abc123",
  "status": "confirmed",
  "handle": "@satvi",
  "purpose": "Concert ticket purchase",
  "verificationLevel": "ping",
  "verifiedAt": "2026-03-07T14:30:00Z"
}

Verifying signatures

Every webhook includes an X-AmHuman-Signature header. Verify it using your webhook secret (found in your dashboard) to ensure the request is authentic.

import crypto from 'crypto';

app.post('/webhook/amhuman', (req, res) => {
  const signature = req.headers['x-amhuman-signature'];
  const expected = 'sha256=' + crypto
    .createHmac('sha256', process.env.AMHUMAN_WEBHOOK_SECRET)
    .update(JSON.stringify(req.body))
    .digest('hex');

  if (signature !== expected) {
    return res.status(401).send('Invalid signature');
  }

  const { requestId, status, handle } = req.body;
  // Handle the event...

  res.status(200).send('OK');
});

Delivery guarantees

Webhooks are delivered with 3 retry attempts using exponential backoff (1s, 5s, 25s). Your endpoint should return a 2xx status within 10 seconds. If all retries fail, the event is logged but not re-queued — use the status polling endpoint as a fallback.

Error Codes

CodeMeaningWhat to do
400Bad requestCheck request body — missing or invalid parameters
401UnauthorizedInvalid API key or key type mismatch (using secret key where publishable key is expected)
403ForbiddenDomain not in allowedDomains whitelist
404Not foundHandle doesn't exist or verification request not found
409ConflictUser already has a pending verification — wait for it to complete
410GoneVerification request has expired
429Rate limitedToo many requests — back off and retry

Rate Limits

Rate limits are per-vendor and depend on your plan tier.

TierMonthly verificationsPer minutePrice
Free10010$0
Starter5,00060$49/mo
Pro50,000300$199/mo
EnterpriseUnlimitedCustomContact us

Ready to get started?

Create your vendor account and start verifying humans in minutes.

AmHuman | Proof of Humanity