Two verbs. A scoped, consented identity token, gated by how a person types.
The base URL is https://noctaracorp.com. All endpoints are JSON over HTTPS and CORS-open. There are no SDKs to install for the core flow; it is three HTTP calls. pupulcorp.com is the front door; noctaracorp.com is the issuer that signs, verifies, and revokes.
One curl. It returns the exact response shape a real check returns, from the same code paths, over a fixture record that says so in its first field. Real records need a key and the person's recorded consent.
curl "https://noctaracorp.com/api/v1/registry-demo"
Four claims come back: is_human, is_continuous, has_deviated, stands_behind, each with the evidence and thresholds behind it. A claim we cannot evidence is null, never false. Full registry docs live at noctaracorp.com/developers.
Prerequisite: the person you test with has taken the free read at noctaracorp.com/take (four minutes, no signup). Then:
# 1. Mint your credentials (one call, no human in the loop) curl -X POST https://noctaracorp.com/api/oauth/register \ -H "Content-Type: application/json" \ -d '{"app_name":"My App","email":"you@yourapp.com","redirect_uris":["https://yourapp.com/callback"]}' # 2. Send the person to consent (browser) https://noctaracorp.com/api/oauth/authorize?client_id=app_...&redirect_uri=https://yourapp.com/callback&scope=word%20rhythm%20force&response_type=code&state=xyz # 3. Exchange the code, then read the person (server) curl -X POST https://noctaracorp.com/api/oauth/token -d 'grant_type=authorization_code&code=...&client_id=app_...&client_secret=psk_...&redirect_uri=https://yourapp.com/callback' curl -X POST https://noctaracorp.com/api/pupul-context -H "Authorization: Bearer ACCESS_TOKEN" -H "Content-Type: application/json" -d '{}'
That last call returns the consented read and an AI greeting you can seed straight into your own model's system prompt. Pass {"greet": false} for the raw read only; it is faster and never touches a model.
The production lane. Standard OAuth 2.0 authorization code, discoverable at /.well-known/oauth-authorization-server. The person consents on our screen with their email and mark; your app receives an ES256 token you can verify offline forever against /.well-known/jwks.json.
1. Mint credentials, self-serve, one call:
curl -X POST https://noctaracorp.com/api/oauth/register \
-H "Content-Type: application/json" \
-d '{
"app_name": "My AI App",
"email": "you@yourapp.com",
"redirect_uris": ["https://yourapp.com/callback"],
"public": false
}'
-> { "ok": true, "client_id": "app_...", "client_secret": "psk_..." }
The secret is shown once and stored only as a hash. Set "public": true for a browser-only app (no secret; PKCE S256 required). Rotate any time with { "action": "rotate", "client_id", "client_secret" } to the same endpoint.
2. Send the person to consent at /api/oauth/authorize?client_id&redirect_uri&scope=word rhythm force&response_type=code&state=..., then exchange the code server-side at /api/oauth/token. Or skip the plumbing in a browser app:
<script src="https://noctaracorp.com/sdk.js"></script>
Pupul.signIn({ clientId: "app_...", redirectUri: location.origin + "/callback" });
// on /callback:
const tok = await Pupul.handleCallback({ clientId: "app_...", redirectUri: location.origin + "/callback" });
3. One call turns the sign-in into understanding. The Context API returns the consented read plus a greeting already personalized by an AI, ready to seed your own model's system prompt:
POST /api/pupul-context Authorization: Bearer <access_token>
-> { "ok": true, "word": "...", "rhythm": "...", "force": "...", "ai_message": "..." }
Meter and price: every consented read is metered. Check your usage with your own credentials at GET /api/oauth/usage (Basic auth). The first 1,000 reads each month are free per app. Past that the endpoint returns 402 free_tier_exhausted with an upgrade_url. Subscribe to the Developer plan, 49 dollars a month, which includes 25,000 reads, at buy.stripe.com/eVqcN52Ee4kNeSDe2x8AE03 and enter your app's client_id at checkout; your cap lifts within seconds of payment, no email, no waiting. Reads beyond the free 1,000, and beyond the plan's 25,000, are 5 cents a read (0.05 dollars), arranged with us before they bill, never charged by surprise. That is the whole price list for this API: 1,000 free reads a month per app, 49 a month for 25,000, 0.05 a read after that. Two behaviors worth knowing: {"greet": false} skips the AI greeting for a faster, cheaper raw read, and under extreme global load the greeting may return ai_message_capped: true while the read itself always flows.
word rhythm force. Every grant is revocable by the person at noctaracorp.com/identity, and revocation kills the token everywhere.A person has a read on file (a word and a rhythm, taken once at noctaracorp.com). They enroll a keystroke signature. When your app needs their identity, they authorize a scoped grant by typing their phrase; you receive a token. You verify the token to read the consented claims and the presence label.
POST /api/identity-enroll
{
"email": "person@example.com",
"phrase": "their word or short phrase",
"samples": [ [ {"k":"a","d":0,"u":92}, ... ], ...x4 ]
}
Each sample is the keystroke timing of one typed attempt: per key, d = keydown ms and u = keyup ms, both relative to the first keydown. Send at least 3 (4 is better). We store only a derived reference, never the phrase. Returns { ok, enrolled, self_min }.
POST /api/identity-grant
{
"email": "person@example.com",
"app_id": "your.app",
"scope": "word rhythm force",
"phrase": "their phrase",
"kd": [ {"k":"a","d":0,"u":90}, ... ],
"require_presence": true
}
Allowed scopes: word, rhythm, force. The person consents to exactly these, and nothing deeper is grantable: the half-truth and the compliance lever never leave the person's own room. With require_presence: true, the grant returns 401 unless the keystroke rhythm verifies. Returns a signed token plus the presence result. One difference worth knowing: this grant lane signs HS256 on a secret only we hold, so its tokens are verified by calling /api/identity-verify. The OAuth lane above signs ES256 and is the one you can verify offline against the JWKS. If you want offline verification, use OAuth.
{
"ok": true,
"token": "<jwt>",
"scope": "word rhythm force",
"presence": { "level": "verified", "confidence": 0.77 },
"expires_at": "..."
}
| presence.level | meaning |
|---|---|
verified | keystroke rhythm matched (confidence ≥ 0.65). Token amr includes keystroke. |
weak | partial match (0.5 to 0.65). Treat with caution. |
failed | did not match. With require_presence, the grant is refused. |
unverified | no keystroke sample sent, or no enrollment on file. Email-only trust. |
POST /api/identity-verify with { token }, or Authorization: Bearer <token>. This is the verifier for the HS256 grant lane. OAuth access tokens are ES256 and need no call to us at all: fetch /.well-known/jwks.json once and verify them yourself, forever. Returns the consented claims and presence:
{
"ok": true, "valid": true,
"claims": {
"sub": "<mark>", "aud": "your.app", "scope": "word rhythm force",
"amr": ["email","keystroke"], "presence": "verified", "presence_conf": 0.77,
"word": "...", "rhythm": "...", "force": "...", "exp": 0
}
}
Revoked or expired tokens return 401. A person can revoke any grant from their identity page; verification fails immediately after.
Email and passwords prove what a person knows. As agents act on people's behalf, the question becomes whether a real, specific human is present at the moment of consent. The presence label is an honest answer to that, bound into the token, so a relying party can require it for high-stakes actions and skip it for low-stakes ones.
No key request needed for the OAuth rail: POST /api/oauth/register mints your credentials on the spot. Building something unusual and want the founder in the loop? Ask here.