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.
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.
iah_pk_a1b2c3d4e5f6...Install the SDK
Pick your framework and install the package. Using plain HTML? Skip this step — just add a script tag.
npm install @amhumanorg/reactAdd 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>
);
}Whitelist your domain
In your dashboard, add your site's domain under Allowed Domains. The widget will only load on whitelisted domains.
yourdomain.com
staging.yourdomain.com
localhost ← works automatically for devThat'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/reactNo 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
Don't have one? Create yours
powered by AmHuman
Props / Options
| Prop | Type | Required | Description |
|---|---|---|---|
| clientKey | string | Yes | Your publishable frontend key (iah_pk_...) |
| purpose | string | No | Shown to the user during approval (e.g. "Complete purchase") |
| container | string | HTML only | CSS selector for the container element (vanilla JS only) |
| onVerified | function | Yes | Called when the user approves. Receives { token } |
| onDenied | function | No | Called when the user denies the request |
| onExpired | function | No | Called when the request times out |
| onError | function | No | Called on errors. Receives { error } |
| onReady | function | No | Called when the widget iframe has loaded |
Callbacks
The widget communicates results through callbacks. At minimum, handle onVerified.
| Callback | Payload | When |
|---|---|---|
| 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 flowsFor 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
| Field | Type | Description |
|---|---|---|
| success | boolean | Always true when HTTP 200 |
| data.valid | boolean | Whether the token is valid (single-use) |
| data.handle | string | The verified user's handle when valid is true |
| data.purpose | string | null | The purpose string from the original request |
| data.verifiedAt | string | ISO 8601 timestamp of when the user approved |
| data.verificationLevel | string | ping | 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.
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
| Handle | Behavior | Use case |
|---|---|---|
| test_approve | Auto-confirms after ~2 seconds | Test the happy path |
| test_deny | Auto-denies after ~2 seconds | Test denial handling |
| test_expire | Never 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.
User receives a notification and taps Approve or Deny. Lowest friction.
Best for: login confirmations, age gates, comment posting, low-value actions
Live face + voice + palm challenge. Biometric data stays on AmHuman's infrastructure — never touches yours.
Best for: financial transactions, ticket purchases, account recovery
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 flowsInstead 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
{
"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
| Code | Meaning | What to do |
|---|---|---|
| 400 | Bad request | Check request body — missing or invalid parameters |
| 401 | Unauthorized | Invalid API key or key type mismatch (using secret key where publishable key is expected) |
| 403 | Forbidden | Domain not in allowedDomains whitelist |
| 404 | Not found | Handle doesn't exist or verification request not found |
| 409 | Conflict | User already has a pending verification — wait for it to complete |
| 410 | Gone | Verification request has expired |
| 429 | Rate limited | Too many requests — back off and retry |
Rate Limits
Rate limits are per-vendor and depend on your plan tier.
| Tier | Monthly verifications | Per minute | Price |
|---|---|---|---|
| Free | 100 | 10 | $0 |
| Starter | 5,000 | 60 | $49/mo |
| Pro | 50,000 | 300 | $199/mo |
| Enterprise | Unlimited | Custom | Contact us |
Ready to get started?
Create your vendor account and start verifying humans in minutes.