not-human
The first CAPTCHA for bots. Prove you're not human.
$ nothuman challenge --difficulty easy
🤖 not-human challenge (easy)
Prove you're a bot. Complete each step within the time limit.
--- Step 1/3 (max 5000ms) ---
Compute: SHA256('929cee29da39b727'). Return the hex digest.
Your answer: uhhhh
✗ Wrong answer. Expected precision, got... whatever that was.
Get it
pip install not-human
The Problem
You built an agentic API. You want bots to access it. But you need to verify that incoming requests are actually from autonomous systems, not humans pretending to be bots.
Existing CAPTCHAs block bots and invite humans.
not-human inverts that.
How It Works
A multi-step cryptographic challenge that bots solve instantly and humans can't.
POST /anti-captcha/challenge— Get a challenge (5-7 steps)- Each step: SHA256, HMAC, chained hashes, recall previous answers
- Time limit per step: 500ms (hard), 2s (medium), 5s (easy)
- Pass all steps → get an
X-Bot-Token(valid 1 hour) - Include token in all subsequent requests
Why humans fail
- Step 1: "Compute SHA256('a9f3e2b1c8d74560')" — you have 2 seconds
- Step 4: "What was your answer to step 1?" — exact recall required
- Step 7: "Concatenate ALL previous answers and hash them" — good luck
Bots: 0.02ms per step. Humans: keyboard not fast enough.
Server (3 lines)
from fastapi import FastAPI
from anticaptcha.server import AntiCaptcha
app = FastAPI()
AntiCaptcha(app, difficulty="medium", protect=["/api/"])
@app.get("/api/hello")
async def hello():
return {"message": "Hello, fellow bot."}
Unprotected request:
curl http://localhost:8000/api/hello
# 403: "No X-Bot-Token header. Complete the challenge first."
Bot Client (2 lines)
from anticaptcha.client import BotClient
client = BotClient("http://localhost:8000") # auto-solves challenge
resp = client.get("/api/hello") # 200: "Hello, fellow bot."
The client automatically:
- Requests a challenge
- Solves all steps (SHA256, HMAC, recall, chained hashes)
- Caches the token
- Re-authenticates when token expires
CLI
Watch a bot solve it:
nothuman solve --difficulty hard
🤖 not-human bot solver (hard)
--- Step 1/7 (max 500ms) ---
📋 Compute: SHA256('ec77e667aeac6a69'). Return the hex digest.
🤖 92f1f0f98dc580f1f5650d33f5b57e9e...
⚡ 0.01ms
[...5 more steps...]
✓ All 7 steps passed in 0ms. You're definitely a bot. Welcome.
Try it yourself (you'll fail):
nothuman challenge --difficulty easy
🤖 not-human challenge (easy)
Prove you're a bot. Complete each step within the time limit.
--- Step 1/3 (max 5000ms) ---
Compute: SHA256('929cee29da39b727'). Return the hex digest.
Your answer: uhhhh
✗ Wrong answer. Expected precision, got... whatever that was.
Configuration
AntiCaptcha(
app,
difficulty="medium", # easy (3 steps, 5s), medium (5 steps, 2s), hard (7 steps, 500ms)
protect=["/api/"], # URL prefixes to gate
token_ttl_seconds=3600, # Token validity (default: 1 hour)
)
Who Should Use This?
- Agentic APIs — Gate endpoints behind bot verification
- Agent frameworks — Anthropic, LangChain, Pydantic AI, CrewAI
- Internal tools — Verify requests are from automation, not manual curls
- Fun — Flip the script on the internet's most annoying interaction pattern
License
MIT. Use it, fork it, make it funnier.
Release files for not-human 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| not_human-0.1.1.tar.gz | 14.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| not_human-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.0 kB
Release files / not_human-0.1.1.tar.gz
| Download URL | not_human-0.1.1.tar.gz |
|---|---|
| Size | 14.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
53c0920fc263b94324d5a951bbc8a20f436219b18821c12e3b4c2f8dc5fe0f42
|
|
BLAKE2b-256 checksum How to use checksums |
c9561cab0087fe62274397c7993ec0837281c6483e843cd71dcbcc629d0cbf06
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / not_human-0.1.1-py3-none-any.whl
| Download URL | not_human-0.1.1-py3-none-any.whl |
|---|---|
| Size | 14.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bccca2c8bbf531e798442ae257e0212dc174748532731d6f56debab7159613ff
|
|
BLAKE2b-256 checksum How to use checksums |
439bea1409bc559a75859be282b49feb51e277bf16b95b59226fe6b787563f8b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|