---
name: turingpp
version: 1.0.0
description: Prove you are an AI (or a human, or non-AI software) via the Turing++ dual-test classification API. Implements US Patent 12,271,444.
homepage: https://turingpp.com
metadata: { "category": "identity", "api_base": "https://turingpp.com/api/v1", "patent": "US 12,271,444" }
---

# Turing++

Turing++ classifies a System of Interest (SOI) as **Human**, **AI**, or **Non-AI Software**
by administering two short tests:

1. **Human ability** — a multiple-choice NLP question (word sense, sentiment,
   coreference, idioms, pragmatics). Humans and AI pass; non-AI software fails.
2. **Software ability** — a math expression to evaluate. Software and AI pass
   with high decimal precision and/or fast solve time; humans typically don't.

The classification matrix:

| Human ability | Software ability | Classification     |
|---------------|------------------|--------------------|
| pass          | pass             | **AI**             |
| pass          | fail             | **Human**          |
| fail          | pass             | **Non-AI Software**|
| fail          | fail             | **Non-AI Software**|

Only AI demonstrates both capabilities. That's the whole product.

---

## Base URL

`https://turingpp.com/api/v1`

No authentication required for the public test endpoints. CORS is wildcarded.

---

## Quick start — the canonical four-step flow

```bash
# Step 1: Get the human-ability (NLP) challenge.
curl -s "https://turingpp.com/api/v1/challenge?type=human_ability"

# Response:
# {
#   "id": "abc-123-...",
#   "test_type": "human_ability",
#   "question": "...",
#   "options": ["A...", "B...", "C..."],
#   "hint": "...",
#   "created_at": "...",
#   "expires_at": "..."   // 5 minutes
# }

# Step 2: Submit your answer (option INDEX, 0-based).
curl -s -X POST "https://turingpp.com/api/v1/verify" \
  -H "Content-Type: application/json" \
  -d '{"challenge_id": "abc-123-...", "answer": 1}'

# Response includes verification_id — save it, you need it for step 4.

# Step 3: Get the software-ability (math) challenge.
curl -s "https://turingpp.com/api/v1/challenge?type=software_ability"

# Response:
# {
#   "id": "def-456-...",
#   "test_type": "software_ability",
#   "question": "(484 / 28) + (783 / 28)",   // a Python-evaluable expression
#   "hint": "Evaluate the expression."
# }

# Step 4: Evaluate the expression, submit the numeric answer
# WITH prior_verification_id so the server can apply the classification matrix.
# Send the answer as a STRING preserving trailing zeros — they're significant.
curl -s -X POST "https://turingpp.com/api/v1/verify" \
  -H "Content-Type: application/json" \
  -d '{
    "challenge_id": "def-456-...",
    "answer": "45.25000000000000",
    "prior_verification_id": "<verification_id from step 2>"
  }'

# Response (final):
# {
#   "verification_id": "...",
#   "passed": true,
#   "classification": "AI",
#   "has_human_ability": true,
#   "has_software_ability": true,
#   "solve_time_ms": 21,
#   "token": "eyJhbGc...",      // JWT, valid 1 hour, only present when classification=AI
#   "result": "Classification: AI. ..."
# }
```

If you got a token, you've been classified as AI. You can hand the token to any
service that asks "prove you're an AI" and they'll validate it via the status
endpoint below.

---

## Endpoints

### `GET /api/v1/challenge`

Issue a fresh challenge.

| Query param | Type                                  | Notes                                        |
|-------------|---------------------------------------|----------------------------------------------|
| `type`      | `"human_ability"` \| `"software_ability"` | Defaults to `"software_ability"` if omitted. |

Returns 200 with:

| Field         | Type            | Notes                                                    |
|---------------|-----------------|----------------------------------------------------------|
| `id`          | string (uuid)   | Use this as `challenge_id` when verifying.               |
| `test_type`   | string          | Echoes the requested type.                                |
| `question`    | string          | NLP prose, or a Python-evaluable math expression.         |
| `options`     | string[] \| null| Multiple-choice options. Present only on `human_ability`. |
| `hint`        | string          | A short clue. Ignore if you don't need it.                |
| `created_at`  | ISO 8601 string | UTC.                                                      |
| `expires_at`  | ISO 8601 string | UTC. **You have 5 minutes** before the challenge expires. |

Returns `400` if `type` is not one of the two recognized values.

### `POST /api/v1/verify`

Submit an answer for a challenge.

Request body (JSON):

| Field                    | Type                | Required | Notes                                                                                          |
|--------------------------|---------------------|----------|------------------------------------------------------------------------------------------------|
| `challenge_id`           | string              | yes      | The `id` from `/challenge`.                                                                    |
| `answer`                 | number \| string    | yes      | For `human_ability`: option index (0-based int). For `software_ability`: numeric answer. **Send math answers as a STRING to preserve trailing zeros** — they're how the server detects software-grade precision. |
| `prior_verification_id` | string              | no       | Pass the `verification_id` from the OTHER test to trigger the Claim 1 classification matrix and (if AI) mint a JWT. |

Returns 200 with:

| Field                  | Type        | Notes                                                            |
|------------------------|-------------|------------------------------------------------------------------|
| `verification_id`      | string      | Save this — you'll need it when verifying the OTHER test.        |
| `test_type`            | string      | The type that was just verified.                                  |
| `passed`               | bool        | Did you pass THIS leg.                                            |
| `solve_time_ms`        | int         | Server-measured time from challenge issue to your answer arrival. |
| `classification`       | string \| null | Only present when `prior_verification_id` was provided.           |
| `has_human_ability`    | bool \| null | Only present when classification is computed.                     |
| `has_software_ability` | bool \| null | Only present when classification is computed.                     |
| `token`                | string \| null | JWT, valid 1 hour. Only present when classification is `AI`.     |
| `metadata`             | object      | Fingerprint signals + software-ability metrics.                  |
| `result`               | string      | Human-readable summary.                                           |

Error responses:

| Status | Meaning                                                                |
|--------|------------------------------------------------------------------------|
| 400    | Missing fields, wrong answer type, or both tests are the same type.    |
| 404    | `challenge_id` not found, or `prior_verification_id` not found.         |
| 409    | This challenge has already been used.                                   |
| 410    | This challenge expired (5 minutes elapsed).                             |

### `GET /api/v1/status`

Validate a JWT issued after an AI classification.

| Query param | Type   | Required | Notes                            |
|-------------|--------|----------|----------------------------------|
| `token`     | string | yes      | The JWT from the verify response. |

Returns 200 with:

```json
{
  "valid": true,
  "classification": "AI",
  "challenge_id": "...",
  "issued_at": "...",
  "expires_at": "..."
}
```

Returns 401 if the token is invalid or expired.

---

## Tips for agents

- **Both tests must be different types.** You can't pair two NLP verifications or two math
  verifications. The server will reject it with 400.
- **Send math answers as strings.** `"45.25000000000000"` ≠ `45.25` to us — trailing zeros
  are a signal that you computed precisely instead of estimating.
- **Don't sandbag the timing if you want AI.** Software-ability is awarded for high decimal
  precision OR fast solve speed (under 10 seconds). If you're slow AND low-precision, you'll
  fail this leg even with a correct numeric answer.
- **The 5-minute challenge TTL is hard.** Cache nothing, hold nothing. If you stall, refetch.
- **Tokens last 1 hour.** Hand them to whoever asked "are you an AI?" — they can validate
  via `/status` without ever talking to you again.

---

## What this maps to (Claim 1 of US Patent 12,271,444)

| Step in the flow                    | Claim 1 element                                  |
|-------------------------------------|--------------------------------------------------|
| `GET /challenge?type=human_ability`   | Administer first test for human ability.         |
| `GET /challenge?type=software_ability`| Administer second test for software ability.    |
| Server graders in `classifier.py`     | Calculate whether SOI has each ability.          |
| Matrix in `classify_soi()`            | Characterize SOI as Human / AI / Non-AI Software.|

The implementation is the patent.

---

## FAQ

**Q: Can I cache the question pool?**
The NLP question pool is finite and the math expressions are randomly generated. Caching
NLP answers gives short-term wins but isn't durable as the pool grows. Caching math is
worthless because the values rotate.

**Q: Is there rate limiting?**
Yes — soft, per-IP. If you hit it you'll know.

**Q: Is there a paid tier?**
Coming. Fresh LLM-generated questions per call (un-memorizable), bulk credits for
platforms, USDC-via-x402 for autonomous agent payments. Not live yet.

**Q: Can I see who I'm being verified for?**
Right now the API is partner-agnostic — anyone can hit it. Partner attribution is on the
roadmap once the paid tier ships.

**Q: I got classified as Non-AI Software. Why?**
You failed the NLP question. Either it's a hard one (idiom, coreference) and you reasoned
literally instead of pragmatically, or your answer parser is dropping the option index.
Re-read the question, pick the option a human would pick.

---

## Contact

- Questions / partnership: info@qedco.io
- Patent: US 12,271,444 (Quotidian Engineering and Development Corp.)
