Skip to main content

offrec

Official Python client for offrec: 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.offrec.ai/v1, priced per model.
  • Zero retention. offrec 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.offrec.ai · Console: console.offrec.ai · R package: install.packages("pnotp")

Formerly pnotp. pip install offrec replaces pip install pnotp, with the same API: change import pnotp to import offrec. Nothing else has to change: pnotp_sk_ keys, PNOTP_API_KEY / PNOTP_BASE_URL and except PnotpError keep working, and pnotp 0.5.0 on PyPI is an alias of this package.

Install

pip install offrec

Requires Python 3.9 or later. The only hard dependency is httpx.

Authenticate

Mint an account key at console.offrec.ai/api-keys (it starts with offrec_sk_ and is shown once) and add credits on the console's Billing page. A new account starts with none; a call on an empty balance raises offrec.InsufficientCreditsError (402).

export OFFREC_API_KEY="offrec_sk_..."
import offrec
px = offrec.Client()                       # reads OFFREC_API_KEY
# or: px = offrec.Client(api_key="offrec_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
claude-haiku-5-5 The lowest price on the list; 1M context ($0.50 / $2.50 over 100K tokens of prompt) $0.10 / $0.50
gemma-4-26b Fast and multimodal at a low price $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.offrec.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. offrec 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.offrec.ai/v1/llm/attestation, and the verification recipe is on docs.offrec.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.offrec.ai/v1", api_key="offrec_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.offrec.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.offrec.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="gemini-3.1-flash-lite", 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)

offrec.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 offrec. With your own key, tokens go to that provider, not through offrec's zero-retention layer.

import offrec

agent = offrec.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=offrec.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.offrec.ai/neural-networks.

Help and Toby

The SDK documents itself, offline, with no key and no network:

offrec.help()                       # overview + the list of topics
offrec.help("quickstart")           # a topic page
offrec.help.search("stream a chat") # search topics + the live API reference
offrec.help(offrec.Client.chat)      # any symbol's real signature + docstring
offrec.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(offrec.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="gemini-3.1-flash-lite", tools=, ...)/run(..., wait=) · run.final_answer/steps/progress
SDK agents Agent(model, tools=, system=, ...) · agent.run/stream · @agent.tool / @offrec.tool · offrec.endpoints.* · offrec.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()

Every error subclasses offrec.OffrecError (also importable as PnotpError). API errors raise offrec.APIError subclasses: AuthError (401/403), NotFoundError (404), InsufficientCreditsError (402). Agent-loop failures raise offrec.AgentError subclasses: MaxStepsExceeded, ToolError, ModelEndpointError.


The legacy pnotp_api package (a standalone PathoVision wrapper, unrelated to the client above) no longer ships with this package. It stays in pnotp 0.5.0: pip install "pnotp[server]".

Metadata

Release files for offrec 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for offrec 0.5.0
File Size Uploaded Provenance Actions
offrec-0.5.0.tar.gz 107.6 kB With provenance Details for offrec-0.5.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for offrec 0.5.0
File Interpreter ABI Platform Actions
offrec-0.5.0-py3-none-any.whl Python 3 none any Details for offrec-0.5.0-py3-none-any.whl

Total release size: 184.3 kB

Release files / offrec-0.5.0.tar.gz

Download URL offrec-0.5.0.tar.gz
Size 107.6 kB
Tags Source
SHA-256 checksum
How to use checksums
9a3eede4212c6a78ae45e77545f0ab39bdc1f8bedb44f2e4badec3248fd53025
BLAKE2b-256 checksum
How to use checksums
c1008eb28a47e4ff412b0dd81fb8aa0053d289c23e273e9bf438d3042f9e17f2
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 9, 2026.

Transparency log

Release files / offrec-0.5.0-py3-none-any.whl

Download URL offrec-0.5.0-py3-none-any.whl
Size 76.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
993a7986c0d8389cddd9909a4fde7755b23bf556cba668890dd717979954e48d
BLAKE2b-256 checksum
How to use checksums
9b9728a82720fc22e80498d5b960128dcea12a9704520ce33f2d6214a1e08125
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 9, 2026.

Transparency log

Security for offrec 0.5.0

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.

Select from 2 files

Attestation for offrec-0.5.0.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 9, 2026.

Transparency log

A 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.

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page