ziffer
The ZIFFER client for Python. Propose an action, wait for the decision, and verify the signed receipt in your own process before you act.
Install
pip install ziffer
Python 3.10 or later.
Quickstart
import json, os
from ziffer import Client, TrustAnchor, verify
client = Client(base_url=os.environ["ZIFFER_API_URL"], api_key=os.environ["ZIFFER_API_KEY"])
anchor = TrustAnchor.from_file(
os.environ["ZIFFER_TRUST_ANCHOR"], min_suite=os.environ["ZIFFER_SUITE_FLOOR"]
)
decision = client.wait(client.propose(proposal).decision_id, timeout=30.0)
if decision.outcome != "ALLOW":
raise PermissionError(f"ziffer refused: {decision.clause}")
verify(decision.receipt, json.dumps(proposal).encode(), anchor)
bank.transfer(amount, to_account) # your line, unchanged
You pass the proposal twice on purpose. The verifier hashes the bytes you hand it and compares them with the receipt's claim. The check is against your copy, not against ours. Key order and spacing do not matter.
verify checks the answer. Your own if is what stops the action.
An action that needs human approval answers ATTEST and no receipt. Keep polling client.wait
for the same decision id until decision.receipt is present, then verify it.
Configuration
| Variable | What it is | Where the value comes from |
|---|---|---|
ZIFFER_API_KEY |
Your API key. It carries your tenant, so no request names a tenant. | We issue it. It expires after 90 days unless you ask for another lifetime. |
ZIFFER_TRUST_ANCHOR |
Path to the public key file your receipts are signed under. | We give you the file. Take it from us, never from the API you are checking. |
ZIFFER_SUITE_FLOOR |
The weakest signature suite you will accept. | You choose it. There is no default. |
ZIFFER_API_URL |
The base URL of the ZIFFER deployment you call. | We give it to you with your key. |
When a request is refused
Every refusal is a raised RefusedError whose name names the rule that fired; the table of
every clause, what it means and what to do is at https://ziffer.io/docs/refusals. Catch
RefusedError, record the name, and do not retry it. A ConnectionError from propose is a
different thing: you never got an answer at all.
Documentation
- Quickstart: https://ziffer.io/docs/quickstart
- Integrating the SDK: https://ziffer.io/docs/developers/sdk
- Sandbox tenants: https://ziffer.io/docs/developers/sandbox
- Every refusal: https://ziffer.io/docs/refusals
- Policy by example: https://ziffer.io/docs/policy/by-example
- Glossary: https://ziffer.io/docs/glossary
Support
Write to hello@ziffer.io. Your API key, your trust anchor file and your suite floor come from us. So does an answer about a refusal you cannot explain.
License
Proprietary. Copyright (c) 2026 code75 SASU, Paris, France. ZIFFER is a registered trademark of
code75 SASU. This package is not open source. Its use is governed by your agreement with code75
and by LICENSE beside this file. The open-source components it redistributes are listed in
THIRD-PARTY-NOTICES, under their own licences.
Release files for ziffer 0.1.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 | |
|---|---|---|---|
| ziffer-0.1.1.tar.gz | 92.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ziffer-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 176.1 kB
Release files / ziffer-0.1.1.tar.gz
| Download URL | ziffer-0.1.1.tar.gz |
|---|---|
| Size | 92.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e3d112de4fa43f91e1fbe28a014cb14d9fd374676d7ac46280191fb1a4a7c34c
|
|
BLAKE2b-256 checksum How to use checksums |
82e4fba64db0dfb4dbf4239669b35664fa250743a27194c57e14c9b1aa664770
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / ziffer-0.1.1-py3-none-any.whl
| Download URL | ziffer-0.1.1-py3-none-any.whl |
|---|---|
| Size | 83.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
57049b5937790e4693d085a135f495f3266e3a5df12fd1a9835e12c53e9b7270
|
|
BLAKE2b-256 checksum How to use checksums |
9799a6bc703ad1752f42e0a08eb1b855f976f7f1eb8264a2760907965e1360df
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|