SDKs and Libraries
Official client libraries for Python and Node.js, plus raw cURL examples for any language. Each SDK provides typed methods for every API endpoint, client-side hash verification, and Ed25519 signature validation with zero vendor lock-in.
Installation
pip install invoanceInitialize the client
Set INVOANCE_API_KEY in your environment and the client picks it up automatically. All subsequent calls are scoped to your organization.
from invoance import InvoanceClient
# Reads INVOANCE_API_KEY from env automatically
async with InvoanceClient() as client:
result = await client.events.ingest(
event_type="user.signed_in",
payload={"user_id": "user_123"},
)
print(result.event_id)
# Or override explicitly
client = InvoanceClient(api_key="invoance_live_xxx")Events
Ingest an event
Records a business event in the append-only ledger.
result = await client.events.ingest(
event_type="policy.approval",
payload={
"policy_id": "pol_8472",
"approved_by": "risk_committee",
"decision": "approved",
},
)
print(result.event_id)Get an event
Retrieve a single event by ID.
event = await client.events.get("evt_01HX…")
print(event.event_type, event.payload_hash)List events
Paginated listing with optional filters.
page = await client.events.list(
page=1, limit=50, event_type="policy.approval"
)
for e in page.events:
print(e.event_id, e.event_type)Verify an event
Compare a hash or raw payload against the anchored event.
result = await client.events.verify(
"evt_01HX…",
payload_hash="a3f2b1c9d4e8f7…",
)
print(result.match_result) # TrueAudit Logs
The audit namespace lives under client.audit. It defaults occurred_at to now, generates the required idempotency key for you, and ships an offline verifier that needs no network call.
Send an event
Append one activity event to an org's signed ledger.
ev = await client.audit.events.ingest(
org="acme-prod",
action="user.signed_in",
actor={"type": "user", "id": "user_123"},
)
print(ev["event_id"])Get an event
Retrieve a single audit event by id.
event = await client.audit.events.get("aevt_01J…")
print(event["action"], event["seq"])List events
Keyset-paginated listing with action, actor, target, and date filters.
page = await client.audit.events.list(
org_id="aorg_01J…", actions="user.signed_in", limit=50
)
for e in page["events"]:
print(e["id"], e["action"])Verify an event offline
Reconstruct the canonical signed bytes and check the Ed25519 signature locally, with no trust in the server's answer.
from invoance import verify_audit_event
event = await client.audit.events.get("aevt_01J…")
result = verify_audit_event(event) # offline, no network call
print(result.valid) # TrueExport events
Queue an async CSV or NDJSON export, then poll for the download URL.
job = await client.audit.exports.create(
org_id="aorg_01J…", format="csv"
)
status = await client.audit.exports.get(job["id"]) # poll until "ready"
print(status["status"], status.get("download_url"))Documents
Anchor a file
RecommendedPass a file path or raw bytes, the SDK reads it, computes the SHA-256 hash, and uploads the original bytes (stored encrypted) for later retrieval. Set skip_original to anchor the hash only without storing the file.
result = await client.documents.anchor_file(
file="./invoice.pdf",
document_ref="Invoice #1042",
event_type="invoice",
metadata={"amount": 5230, "currency": "USD"},
trace_id="9549c332-…", # optional, attach to a trace
)
print(result.event_id)result = await client.documents.anchor_file(
file="./invoice.pdf",
document_ref="Invoice #1042",
skip_original=True,
)
print(result.event_id)Anchor a hash
If you already have the SHA-256 hash, use the low-level method directly.
result = await client.documents.anchor(
document_hash="a94a8fe5ccb19ba61c4c0873d391e987…",
document_ref="Invoice #1042",
)
print(result.event_id)Get a document
Retrieve a document event by ID.
doc = await client.documents.get("9549c332-a52b-…")
print(doc.document_ref, doc.has_original)List documents
Paginated listing with optional filters.
page = await client.documents.list(page=1, limit=50)
for d in page.documents:
print(d.event_id, d.document_ref)Download original document
Retrieve the original file bytes (if uploaded during anchoring).
data = await client.documents.get_original("9549c332-a52b-…")
with open("invoice.pdf", "wb") as f:
f.write(data)Verify a document
Compare a hash against the anchored document.
result = await client.documents.verify(
"9549c332-a52b-…",
document_hash="a94a8fe5ccb19ba61c4c0873d391e987…",
)
print(result.match_result) # TrueAI Attestations
Create an attestation
Anchor an AI input/output pair with model context.
result = await client.attestations.ingest(
type="output",
input="What is the company refund policy?",
output="Our refund policy allows returns within 30 days...",
model_provider="openai",
model_name="gpt-4.1",
model_version="2026-01-01",
user_id="user_7b1c",
session_id="sess_4f9a",
trace_id="9549c332-…", # optional, attach to a trace
)
print(result.attestation_id, result.payload_hash)Get an attestation
Retrieve the full attestation record with cryptographic metadata.
att = await client.attestations.get("9549c332-a52b-…")
print(att.attestation_type, att.signature_alg)List attestations
Paginated listing with optional filters.
page = await client.attestations.list(
page=1, limit=50,
attestation_type="output",
model_provider="openai",
)
for a in page.attestations:
print(a.attestation_id, a.model_name)Get raw canonical payload
Retrieve the original JSON that was hashed and signed. Useful for independent verification.
raw = await client.attestations.get_raw("9549c332-a52b-…")
print(raw["type"], raw["payload"]["input"])Verify by hash
Compare a SHA-256 hash against the anchored attestation.
result = await client.attestations.verify(
"9549c332-a52b-…",
content_hash="8c74176675eed4e2ff88bc0182af…",
)
print(result.match_result, result.matched_field)Verify by raw payload
SDK onlyPass the raw payload directly, the SDK hashes it client-side and calls the verify endpoint. Accepts a dict/object, JSON string, or raw bytes.
result = await client.attestations.verify_payload(
"9549c332-a52b-…",
payload={
"type": "output",
"payload": { "input": "...", "output": "..." },
"context": { "model_provider": "openai", ... },
"subject": None,
},
)
print(result.match_result) # TrueVerify Ed25519 signature
SDK onlyFetches the attestation and verifies the Ed25519 signature entirely client-side using the public key. Proves no field has been tampered with, including the timestamp. Zero trust in the server required.
# Requires PyNaCl: pip install PyNaCl
result = await client.attestations.verify_signature("9549c332-a52b-…")
print(result.valid) # True
print(result.signed_data) # The exact JSON that was signed
print(result.signed_data["created_at"]) # Timestamp is coveredTraces
Create a trace
Create a new open trace to group events, documents, and AI attestations into a verifiable process proof.
result = await client.traces.create(
label="Vendor Onboarding, Acme Corp",
metadata={
"department": "procurement",
"initiated_by": "j.smith@acme.com"
}
)
print(result.trace_id)List traces
Paginated listing of traces with optional status filter.
page = await client.traces.list(page=1, limit=50, status="open")
for t in page.traces:
print(t.trace_id, t.label, t.status)Get a trace
Retrieve a single trace with event summaries.
trace = await client.traces.get("tr_abc123…")
print(trace.trace_id, trace.event_count, trace.status)Seal a trace
Initiate sealing to compute composite hash and lock the trace from further events.
result = await client.traces.seal("tr_abc123…")
print(result.status) # "sealing"
# Poll for completion:
while True:
trace = await client.traces.get("tr_abc123…")
if trace.status == "sealed":
breakExport proof bundle
Retrieve the complete proof bundle for a sealed trace with all events and signatures.
bundle = await client.traces.proof("tr_abc123…")
print(bundle.composite_hash, bundle.event_count)
for event in bundle.events:
print(event.event_id, event.signature)