chitmark (Python)
Official Python SDK for Chitmark: trust decisions on agent-mediated actions, tuned by business outcomes.
AI agents and multi-account farms drain free tiers, trial credits, and API allowances while looking exactly like your best customers. Chitmark scores each action in under 50 ms and returns allow, challenge, or deny. Then your outcomes (conversion, credit burn, chargeback) come back through feedback and tune the next decision.
Requires Python >= 3.10. Fully typed (py.typed), synchronous httpx under the hood.
Try it without a key: run the playground. Live service health: chitmark.com/status.
Install
pip install chitmark
# or
uv add chitmark
Quick start
from chitmark import Chitmark
with Chitmark(api_key="ck_live_...") as client:
verdict = client.verify(
action="signup",
session="sess_9f3a",
surface="app.acme.com/signup",
subject={
"email": "buyer@acmecorp.com", # hashed client-side before the wire
"ip": "203.0.113.7", # truncated to /24 client-side
"userAgent": "Mozilla/5.0 ...",
},
)
# Persist verdict["eventId"] on the account row: feedback joins only on that id.
The three verbs
| Method | Endpoint | Purpose |
|---|---|---|
client.verify(...) |
POST /v1/verify |
Decide |
client.feedback(...) |
POST /v1/feedback |
Learn |
client.challenge(...) |
POST /v1/challenge |
Escalate |
Timeouts and transport errors return a degraded challenge verdict and never raise on verify. HTTP errors raise ChitmarkApiError with the status attached. Set on_degraded to challenge, never allow on degraded.
Report outcomes
Store the eventId from verify on the account row, then report outcomes against that same id. Never guess or derive the id.
# At signup: persist the join key
verdict = client.verify(action="signup", subject={"email": "a@b.com"})
db.accounts.update(user_id, chitmark_event_id=verdict["eventId"])
# Later, when a label matures:
client.feedback(
event_id=account.chitmark_event_id, # the stored join key
outcome="credit_burn",
value=87.4, # dollar amount: unit rides along (default "usd")
observed_at="2026-08-06T04:00:00Z",
)
Exact duplicate feedback bodies derive the same warehouse id, so retrying a connector never double-counts a burned value. unit ships only alongside value.
Handle a challenge
When verify returns challenge, issue one, solve the proof locally, and complete it. Proof-of-work difficulty is server-issued (4 by default, up to 6 at higher risk tiers): about 65k hashes, milliseconds for one real user, costly at farm scale.
import hashlib
issued = client.challenge(event_id=verdict["eventId"], session="sess_9f3a")
instructions = issued["instructions"]
if instructions["type"] == "pow":
prefix = "0" * instructions["difficulty"]
nonce = 0
while True:
digest = hashlib.sha256(
f"{issued['challengeId']}:{instructions['seed']}:{nonce}".encode()
).hexdigest()
if digest.startswith(prefix):
break
nonce += 1
client.complete_challenge(
event_id=verdict["eventId"],
challenge_id=issued["challengeId"],
session="sess_9f3a",
proof={"type": "proof_of_work", "nonce": str(nonce)},
)
# Re-verify with context={"challengeId": ...} so the next verdict honors it.
Verify the receipt
Every production verdict ships a verdictToken: an ES256 JWT bound to session, origin, and event. Verify it before acting on high-value decisions (install the verdict extra for the crypto dependency):
pip install "chitmark[verdict]"
from chitmark.verify_token import verify_verdict_token
claims = verify_verdict_token(
verdict["verdictToken"],
session="sess_9f3a", # enforce session binding (recommended)
aud="api.chitmark.com", # enforce origin binding
)
# claims: {"eventId", "decision", "actorType", "confidence", "jti", "exp", ...}
Rejects expired tokens, unknown keys, bad signatures, and session or origin mismatches with typed error codes.
PII modes
| Mode | Behavior |
|---|---|
hashed (default) |
SHA-256 email, /24 IP truncation, allowlisted form fields |
none |
Derived/header-shape signals only |
raw |
Tenant opt-in only; higher compliance review |
Dependency injection and lifecycle
The client owns its httpx.Client by default and closes it on context exit. Pass your own for connection pooling or tests:
import httpx
from chitmark import Chitmark
pool = httpx.Client(base_url="https://api.chitmark.com", timeout=0.8)
client = Chitmark(api_key="ck_live_...", http_client=pool)
Develop
cd packages/sdk-python
uv sync --extra dev # or: pip install -e ".[dev]"
pytest
ruff check .
Agent integration
Using Cursor, Claude Code, Codex, or another coding agent? Point it at
chitmark.com/SKILL.md, or paste this into your
prompt: Integrate Chitmark into my app following https://chitmark.com/SKILL.md.
Resources
License
Proprietary: see LICENSE.
Metadata
Release files for chitmark 0.6.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 | |
|---|---|---|---|
| chitmark-0.6.1.tar.gz | 19.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| chitmark-0.6.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 34.3 kB
Release files / chitmark-0.6.1.tar.gz
| Download URL | chitmark-0.6.1.tar.gz |
|---|---|
| Size | 19.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3ebab56ef87a492aab3e38c9141666ff1beec34be6b3577e79623038e29dcbe9
|
|
BLAKE2b-256 checksum How to use checksums |
0edbf372760d348066d6d2e5c96f3b5bf2555f54119978941b42a245b4d85f46
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / chitmark-0.6.1-py3-none-any.whl
| Download URL | chitmark-0.6.1-py3-none-any.whl |
|---|---|
| Size | 15.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c1be20343a53782586618ec1ae40abd1e88eb3cf2b9cb03417a6c11954a40c8a
|
|
BLAKE2b-256 checksum How to use checksums |
17a50f23da9fe7ce2796fdfa0b108fa925538a611b5c7dae8cef0ec8f775ee76
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|