pnotp
Official Python client for P¬P: zero-retention inference for frontier models. AI off the record.
- Frontier models, one key. Claude, Gemini, Gemma, DeepSeek, Kimi, Qwen and GLM
through
https://api.pnotp.ai/v1, priced per model. - Zero retention. P¬P never stores or logs your prompts or the answers. The models run on managed providers under zero-retention terms.
- A receipt for every call. Signed with Ed25519 and checkable against a public key.
Docs: docs.pnotp.ai · Studio:
studio.pnotp.ai · R package: install.packages("pnotp")
Install
pip install pnotp
Requires Python 3.9 or later. The only hard dependency is httpx.
Authenticate
Mint an account key at studio.pnotp.ai/api-keys
(it starts with pnotp_sk_ and is shown once) and add credits on Studio's Billing
page. A new account starts with none; a call on an empty balance raises
pnotp.InsufficientCreditsError (402).
export PNOTP_API_KEY="pnotp_sk_..."
import pnotp
px = pnotp.Client() # reads PNOTP_API_KEY
# or: px = pnotp.Client(api_key="pnotp_sk_...")
Your first call
out = px.chat("Summarize this clause in one sentence: ...", model="gemini-3.1-flash-lite")
out["completion"] # the answer
out["usage"] # {"input_tokens": ..., "output_tokens": ...}
out["receipt"]["zero_retention"] # True
out["receipt"]["served_by"] # who ran the call, and who governs retention there
Change model to use any model on the list. A few starting points:
model |
Use it for | $ in / out per 1M tokens |
|---|---|---|
gemini-3.1-flash-lite |
The default: fast, reads images, tool calling | $0.25 / $1.50 |
gemma-4-26b |
The lowest price on the list | $0.15 / $0.60 |
deepseek-v4.1-flash |
Agents and 1M-token context at a low price | $0.30 / $1.20 |
claude-sonnet-5-5 |
Coding, agents and knowledge work, 1M context | $2.00 / $10.00 |
claude-opus-5-5 |
Frontier coding and long-horizon agent work | $4.00 / $20.00 |
The live list, with every price and context window, is public:
GET https://api.pnotp.ai/v1/llm/pricing. Gemini and Gemma run on Google Cloud
Vertex AI, Claude on Amazon Bedrock, and DeepSeek, Kimi, Qwen and GLM on
Fireworks AI.
Tools, images and documents
out = px.chat("Book a 3pm slot with Dr. Reyes", tools=[{"type": "function", "function": {...}}])
out.get("tool_calls") # [{"id", "name", "arguments": {...}}]
px.chat("What is in this diagram?", image="diagram.png") # on a model with vision
px.chat("Summarize this contract", file="contract.pdf") # parsed to text
A model sees images natively when its GET /v1/llm/pricing entry says
vision: true. Audio is not enabled today (a clean 422).
The receipt
Every call returns a receipt next to the answer: the retention basis, the model, the tokens, the cost and who served it. It carries no prompt and no answer. P¬P keeps no copy of the call, so store the receipts you need.
The receipt is signed with Ed25519. The public key is at
GET https://api.pnotp.ai/v1/llm/attestation, and the verification recipe is on
docs.pnotp.ai/receipts.
Already on the OpenAI SDK?
The API speaks OpenAI's Chat Completions. Change two lines and keep your code:
from openai import OpenAI
client = OpenAI(base_url="https://api.pnotp.ai/v1", api_key="pnotp_sk_...")
resp = client.chat.completions.create(model="claude-sonnet-5-5", messages=[...], tools=[...])
resp.receipt # the signed receipt
Streaming, tool_choice, the Vercel AI SDK and LangChain work the same way. See
docs.pnotp.ai/migrating.
Laya: typed decisions
Laya answers typed questions (choice, score, yes/no) about a ticket, an email or a conversation with calibrated probabilities, and writes no text.
result = px.decide(
"Checkout has been down for an hour and we're losing sales. Fix it or we cancel.",
{
"queue": {"type": "choice", "instructions": "Which team owns this ticket?",
"criteria": {"infrastructure": "outages, downtime, errors",
"billing": "refunds, invoices, charges"}},
"churn_risk": {"type": "noul", "instructions": "Does the customer threaten to cancel?"},
},
)
result["answers"]["queue"]["choice"] # "infrastructure"
Guide: docs.pnotp.ai/laya.
Hosted agents
A hosted agent runs a tool-calling loop with a zero-retention model as its brain. A data-compliant run keeps no question, no intermediate reasoning and no loop state: only metered metadata and the encrypted final answer, held for 24 hours.
a = px.agents.create("Advisor")
px.agents.publish(a["id"], model="pnotp-compliant", tools=["programs_db"])
run = px.agents.run(a["id"], "I love AI and maths. Which programs fit?", wait=True)
print(run.final_answer())
SDK agents (bring your own brain)
pnotp.Agent is a bounded, observable tool-calling loop that runs in your
process. The brain can be your own provider key (any OpenAI-style
/chat/completions with tool calling) or a text model you deployed on P¬P. With
your own key, tokens go to that provider, not through P¬P's zero-retention layer.
import pnotp
agent = pnotp.Agent("gemini:gemini-2.5-pro", # reads GEMINI_API_KEY
system="You are a careful research assistant.")
@agent.tool
def search_pubmed(query: str, max_results: int = 5) -> list[dict]:
"Search PubMed and return the top hits." # docstring -> tool description
return my_client.search(query, k=max_results) # JSON Schema is derived from the signature
run = agent.run("Recent trials on pediatric pneumonia from chest X-rays?")
print(run.output, run.stop_reason) # final answer + "stop" | "max_steps"
for event in agent.stream("..."): # live UI events
... # TextDelta / ToolCallStarted / ToolCallFinished / StepBoundary / Done
The loop is bounded: max_steps, per-tool tool_timeout, max_tool_retries (a
schema-invalid or timed-out call is re-asked without spending the step budget),
and on_tool_error ("return" feeds the error back to the brain, or "raise").
Pass response_format=MyDataclass for a structured final answer.
Neural networks (an extra)
Training and deploying your own models is a side feature that still works end to end:
project = px.projects.create(name="Chest X-ray", task_type="binary_image_classification")
model = px.models.create(
project["id"], name="cnn-v1",
architecture=pnotp.architectures.image_classifier(num_classes=2),
)
# dataset = a .zip of class-named folders (image) or a .csv (tabular)
job = px.train(model.id, dataset="train.zip", epochs=5)
job.wait(on_progress=lambda j: print(j.status)) # job.pause() / resume() / cancel()
dep = px.deployments.upload(project["id"], name="prod", checkpoint="model.pt", compliant=True)
print(px.predict(dep["deployment"]["id"], "xray.jpg"))
CPU training is free; GPU training bills $1.00 per hour on an NVIDIA L4, per second
of compute. compliant=True makes an endpoint data-compliant: the input is deleted
before the response returns, error text stays out of the stats log, and each
response carries a compliance block. External consumers can call an endpoint with
a per-deployment pnp_... key (px.deployments.create_key(...)). Guide:
docs.pnotp.ai/neural-networks.
Help and Toby
The SDK documents itself, offline, with no key and no network:
pnotp.help() # overview + the list of topics
pnotp.help("quickstart") # a topic page
pnotp.help.search("stream a chat") # search topics + the live API reference
pnotp.help(pnotp.Client.chat) # any symbol's real signature + docstring
pnotp.help.errors # the exception catalog
Toby, the hosted assistant, answers in plain English (needs your key and a positive balance; it falls back to local doc search otherwise, so it never raises):
print(pnotp.help.toby("Which model should I use for long contracts?"))
Surface
| Area | Calls |
|---|---|
| LLM | chat(text_or_messages, model=, tools=, image=, file=, ...) returns {completion, usage, model, receipt} |
| Laya | decide(state, questions, model="laya", min_confidence=) |
| Hosted agents | agents.create/get/list/publish(model="pnotp-compliant", tools=, ...)/run(..., wait=) · run.final_answer/steps/progress |
| SDK agents | Agent(model, tools=, system=, ...) · agent.run/stream · @agent.tool / @pnotp.tool · pnotp.endpoints.* · pnotp.model |
| Credits | credits.balance() |
| API keys | api_keys.create/list/revoke |
| Projects and models | projects.list/create/get · models.create/list/get/add_version/versions |
| Training | train(...) returns a TrainingJob · job.wait/progress/pause/resume/cancel · jobs.list/get |
| Deployments | deployments.upload/list/get/predict/stats/pause/resume/delete · create_key/list_keys/revoke_key |
| Help | help() / help("topic") / help(symbol) · help.search/topics/errors · help.toby(...) · help.as_tool() |
Errors raise pnotp.APIError subclasses: AuthError (401/403), NotFoundError
(404), InsufficientCreditsError (402). Agent-loop failures raise
pnotp.AgentError subclasses: MaxStepsExceeded, ToolError, ModelEndpointError.
The legacy pnotp_api package (a standalone PathoVision wrapper) still ships in
this distribution and is unrelated to the client above.
Metadata
Release files for pnotp 0.4.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 | Provenance | Actions |
|---|---|---|---|---|
| pnotp-0.4.1.tar.gz | 109.8 kB | With provenance | Details for pnotp-0.4.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pnotp-0.4.1-py3-none-any.whl | Python 3 | none | any | Details for pnotp-0.4.1-py3-none-any.whl |
Total release size: 193.8 kB
Release files / pnotp-0.4.1.tar.gz
| Download URL | pnotp-0.4.1.tar.gz |
|---|---|
| Size | 109.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
36568e5a1e71c09327abcf7da483bc25f8ed4f3c2a92a53b5990c44b49dd805a
|
|
BLAKE2b-256 checksum How to use checksums |
45e1c03a068aaee77b6a6a760383ae570782c76f5117b78625839a41e707516d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / pnotp-0.4.1-py3-none-any.whl
| Download URL | pnotp-0.4.1-py3-none-any.whl |
|---|---|
| Size | 84.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1986f471d75b94a280e41dc595e8f1c5359e391bdeb3a6fd630e885fd51b4785
|
|
BLAKE2b-256 checksum How to use checksums |
675b3bb8d2ffab85bac3ed74804fdfdf6a5a836320393696ccc7e15c662d73eb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logSecurity for pnotp 0.4.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for pnotp-0.4.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.