SDKs
Python, TypeScript, CLI, and Go SDKs
Attesto exposes four first-class developer surfaces: Python, TypeScript, Go, and the Attesto CLI. They share the same Proofstream protocol, golden vectors, verifier matrix, production origin, and secret-handling rules.
Package registries
The official package identifiers are attesto for
Python and @attesto/sdk for TypeScript. The current
release family is 0.5.0 across Python, TypeScript,
Go, and CLI, and it is the first release that carries the
Attesto 3 provenance verifiers. The Go
module go.attesto.eu/sdk v0.5.0 and its curve module
go.attesto.eu/sdk/zk v0.5.0 are published. The PyPI
attesto==0.5.0 wheel and the npm
@attesto/sdk==0.5.0 package are published (2026-08-23)
and both registries resolve 0.5.0 as latest; the
signed CLI channel at get.attesto.eu serves
0.5.0 as well, with installers for Linux/macOS
(curl | sh) and Windows
(irm | iex). Install only from the official PyPI and npm
registries; do not install SDKs from mirrors, random tarballs, or
source snapshots.
The release gate separates packages from surfaces: registry
readiness expects three package/module distributions
(attesto, @attesto/sdk, and the Go
module) and four production developer surfaces because the
attesto CLI is a first-class Go-backed verifier
surface. The gate must report surfacesExpected=4,
surfacesReady=4, cliReady=true, and
cliVersionMatches=true.
Package artifacts are intentionally minimal. npm artifacts contain
runtime JavaScript, declaration files, README.md, and
package metadata only. PyPI production releases are wheel-only.
Sourcemaps, raw TypeScript source, tests, caches, source archives,
frontend bundles, API keys, private keys, and secret-like material
are forbidden.
Authentication model
System-key clients are used for event ingest, stream heads, receipts, public proof objects, bundles, and remote verification. Tenant/operator clients use a dashboard bearer token for tenant stream lists, connector installation, Local Vault installation, fork evidence inspection, proof-state views, and tenant audit-pack creation. Do not put either credential in frontend code.
Article 13 support and Article 12 evidence with one integration line
For high-risk AI systems, Article 12 is about technical logging capability and traceability, while Article 13 is about transparency and information that helps deployers and users understand the system. In Attesto terms, the exact one-line integration is export OPENAI_BASE_URL=http://localhost:8765/v1: it points OpenAI-compatible calls at the Attesto Gateway so automatic evidence capture can start. The deterministic attesto report article12 output explains what was recorded and independently verifiable, and teams can use that verified trail as support material for Article 13 documentation. This is evidence support, not a legal conformity statement.
The concrete one-line gateway integration that makes this true is:
export OPENAI_BASE_URL=http://localhost:8765/v1
In production, replace localhost with the deployed
gateway host and keep both the provider key and Attesto system key in
server-side secret storage.
Use this pattern when you own a Python function boundary. The decorator records commitments over arguments, return value, timing, source reference, and failures; the report summarizes coverage without using an LLM.
from attesto import AttestoV2Client, attest, article12
import os
with AttestoV2Client(api_key=os.environ["ATTESTO_API_KEY"]) as capture:
@attest(capture, stream_id="str_...")
def score_case(case: dict) -> dict:
return {"decision": "manual_review", "policy_id": "policy-2026-01"}
score_case({"case_id": "case-2026-0001"})
with AttestoV2Client.with_bearer_token(os.environ["ATTESTO_TENANT_TOKEN"]) as operator:
print(article12(operator, "str_..."))
The capture path uses a system API key; the report path reads tenant stream events and therefore requires a tenant/operator bearer token.
attesto --token-env ATTESTO_TENANT_TOKEN \
report article12 --stream str_... --output report.md
What the SDK handles
The SDKs are intentionally thin server-side clients. They do not hide the evidence model, but they remove repetitive transport work so your application can focus on choosing the right event shape and verifying the returned evidence.
| Concern | SDK behavior | Developer responsibility |
|---|---|---|
| Base URL | Defaults to https://verify.attesto.eu. | Override only for private/staging deployments. |
| Authentication | Supports system API-key mode and tenant bearer-token mode. | Use the narrowest credential needed for the task. |
| Idempotency | Creates idempotency keys for writes when not supplied. | Reuse the same key when retrying the same body from your own job system. |
| Retries | Retries transient 429, 5xx, and transport errors with backoff. | Do not mutate payloads between retries. |
| Proofstream helpers | Exposes stream, receipt, checkpoint, anchor, IVC, bundle, and verify helpers. | Choose stream granularity and policy IDs deliberately. |
| Errors | Raises typed auth, validation, rate-limit, and server errors. | Log safe error categories, not API keys or raw secret-bearing payloads. |
Capability matrix
| Capability | Python | TypeScript | Go | CLI |
|---|---|---|---|---|
| Streams/events/receipts | Yes | Yes | Yes | Yes |
| Windows/checkpoints/consistency | Yes | Yes | Yes | Yes |
| Remote verifier API | Yes | Yes | Yes | Yes |
| Offline receipt verification | Verifier helper/API | Verifier helper/API | Yes | Yes |
| Witness policy and fork evidence | Yes | Yes | Yes | Yes |
| Anchors and IVC epochs | Yes | Yes | Yes | Yes |
| Connectors | Yes | Yes | Yes | Yes |
| Local Vault relay/witness | Yes | Yes | Yes | Yes |
| Provenance verification (Attesto 3): disclosure, bundle provenance, key revocation, effective assurance, ZK range result | Yes (offline) | Yes (offline) | Yes (offline) | No |
| Exact private-numeric opening (Pedersen) | attesto[zk] extra | @noble/curves peer | go.attesto.eu/sdk/zk module | No |
| Release readiness evidence | Via scripts | Via scripts | Via CLI/module tests | Yes |
Python
pip install attesto
import os
from datetime import UTC, datetime
from attesto import AttestoClient
attesto = AttestoClient(api_key=os.environ["ATTESTO_API_KEY"])
ack = attesto.log_event(
type="inference",
status="verified",
ts=datetime.now(UTC),
payload={
"model": "risk-service-v4",
"score": 0.91,
"policy_id": "policy-2026-01",
},
)
print(ack.id)
Python async
import os
from datetime import UTC, datetime
from attesto import AsyncAttestoClient
async with AsyncAttestoClient(api_key=os.environ["ATTESTO_API_KEY"]) as attesto:
ack = await attesto.log_event(
type="ai.decision",
status="verified",
ts=datetime.now(UTC),
payload={"decision": "manual_review", "score": 91},
)
print(ack.id)
TypeScript
npm install @attesto/sdk
import { AttestoClient } from "@attesto/sdk";
const attesto = new AttestoClient({
apiKey: process.env.ATTESTO_API_KEY!,
});
const ack = await attesto.logEvent({
type: "inference",
status: "verified",
ts: new Date(),
payload: {
model: "risk-service-v4",
score: 0.91,
policy_id: "policy-2026-01",
},
});
console.log(ack.id);
TypeScript attestedFetch
Use attestedFetch when an OpenAI-compatible SDK or framework accepts a custom fetch implementation. It records commitments only, never raw prompts or completions. strict: true fails closed when evidence cannot be submitted; fail-open mode must be monitored.
import { AttestoV2Client, attestedFetch } from "@attesto/sdk";
const client = new AttestoV2Client({ apiKey: process.env.ATTESTO_API_KEY! });
const fetchWithEvidence = attestedFetch(client, {
streamId: "str_...",
capture: "commitments",
strict: true,
});
Proofstream v2 client
Use AttestoV2Client when you need stream-level receipts,
checkpoint consistency, witness policy visibility, verifier bundles,
and offline verification helpers.
from attesto import AttestoV2Client
from datetime import UTC, datetime
import os
with AttestoV2Client(api_key=os.environ["ATTESTO_API_KEY"]) as attesto:
stream = attesto.create_stream(
use_case="ai-decision-history",
policy_id="policy-2026-01",
)
receipt = attesto.log_event(
stream_id=stream.stream_id,
source_ref="source-event-001",
event_type="decision",
occurred_at=datetime.now(UTC),
payload={"decision": "review", "score": 91},
)
stored = attesto.get_receipt(receipt.stream_event_id)
report = attesto.verify_receipt(
receipt=stored.receipt,
public_key_hex=os.environ["ATTESTO_RECEIPT_SIGNER_PUBLIC_KEY_HEX"],
stream_event_id=receipt.stream_event_id,
)
assert report.ok
TypeScript Proofstream:
import { AttestoV2Client } from "@attesto/sdk";
const attesto = new AttestoV2Client({
apiKey: process.env.ATTESTO_API_KEY!,
});
const stream = await attesto.createStream({
useCase: "ai-decision-history",
policyId: "policy-2026-01",
});
const receipt = await attesto.logEvent(stream.streamId, {
sourceRef: "case-2026-0001:decision-1",
eventType: "ai.decision",
occurredAt: new Date(),
payload: { decision: "manual_review", score: 91 },
});
const report = await attesto.verifyReceipt({
receipt: receipt.receipt,
streamEventId: receipt.streamEventId,
publicKeyHex: process.env.ATTESTO_RECEIPT_SIGNER_PUBLIC_KEY_HEX!,
});
if (!report.ok) throw new Error(report.problems.join("; "));
Go
Use Go for infrastructure automation, security tooling, cloud workers, and verifier services. The Go SDK currently uses only the Go standard library and is resolved from the public go.attesto.eu/sdk module path.
go get go.attesto.eu/sdk
package main
import (
"context"
"fmt"
"log"
"os"
attesto "go.attesto.eu/sdk"
)
func main() {
client, err := attesto.NewClient(os.Getenv("ATTESTO_API_KEY"))
if err != nil {
log.Fatal(err)
}
stream, err := client.CreateStream(context.Background(), attesto.StreamCreateInput{
UseCase: "ai-decision-history",
PolicyID: "policy-2026-01",
})
if err != nil {
log.Fatal(err)
}
receipt, err := client.LogEvent(context.Background(), stream.StreamID, attesto.EventInput{
SourceRef: "case-2026-0001:decision-1",
EventType: "ai.decision",
Payload: attesto.M{"decision": "manual_review", "score": 91},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(receipt.StreamEventID, receipt.EventHash)
}
CLI
The Attesto CLI is the operator and verifier surface for scripted workflows. It supports JSON output, local config, stream/event actions, receipt verification, bundle verification, fork evidence, quorum evidence, connectors, Local Vault, and release-readiness evidence checks. It never prints stored API keys, tenant tokens, or connector secrets.
Install the signed CLI from get.attesto.eu. The
installers verify the release SHA256 checksum before installing
anything, and the manifest signature can be verified with cosign.
The Homebrew formula and the native Linux packages repackage the
same channel binaries: their hashes come from the cosign-signed
SHA256SUMS manifest, never from a separate build:
# Linux / macOS
curl -fsSL https://get.attesto.eu | sh
# Windows (PowerShell; user-level install, no admin rights)
irm https://get.attesto.eu/install.ps1 | iex
# macOS / Linux (Homebrew)
brew tap attesto/attesto https://git.attesto.eu/attesto/homebrew-attesto.git
brew trust attesto/attesto
brew install attesto
# Native Linux packages: verify the signed manifest first
curl -fsSLO https://get.attesto.eu/0.5.0/SHA256SUMS
curl -fsSLO https://get.attesto.eu/0.5.0/SHA256SUMS.sig
cosign verify-blob --key https://get.attesto.eu/cosign.pub --insecure-ignore-tlog --signature SHA256SUMS.sig SHA256SUMS
# Debian / Ubuntu (run the install as root; arm64 debs and aarch64 rpms
# are on the same channel)
curl -fsSLO https://get.attesto.eu/0.5.0/attesto_0.5.0-1_amd64.deb
sha256sum -c --ignore-missing SHA256SUMS
apt install ./attesto_0.5.0-1_amd64.deb
# Fedora / RHEL (run the install as root)
curl -fsSLO https://get.attesto.eu/0.5.0/attesto-0.5.0-1.x86_64.rpm
sha256sum -c --ignore-missing SHA256SUMS
dnf install ./attesto-0.5.0-1.x86_64.rpm
arm64/aarch64 packages are metadata-verified against the signed manifest but have not been executed on arm hardware.
CLI command reference
| Command group | Subcommands | Use |
|---|---|---|
version, config, login, logout | config get, config set | Inspect version and manage local redacted configuration. |
streams | create, get, head | Create streams, inspect tenant-visible stream metadata, and fetch the append-only head. |
events | log, batch | Submit one event or a JSON event batch with source timestamps and payload files. |
receipts | get, verify | Fetch a stored receipt and verify it locally or through /v2/verify/receipt. |
windows, checkpoints, anchors, ivc | get, verify, checkpoints consistency, ivc epochs get/verify | Fetch and verify Proofstream windows, checkpoint roots, consistency proofs, anchor epochs, and IVC epochs. |
witnesses, quorum, fork-evidence | policies, status, receipts, inspect, verify | Inspect witness policy, proof state, quorum material, and fork evidence. |
bundles, verify | build, get, verify, offline-verify, verify file, verify truth-package | Build verifier bundles and verify bundles, portable receipt files, or Truth Package ZIPs. |
connector, connectors | connector init, connectors create, ingest, revoke, verify | Scaffold connector manifests, manage tenant connectors, ingest events, and verify signed connector payloads. |
local-vault | install, relay, spool, status, witness, fork-evidence, revoke | Operate Local Vault installations, encrypted spool workflows, witness receipts, fork evidence, and revocation. |
marketplace | init, validate, submit | Prepare publisher manifests, validate them locally, and submit assets into private Attesto review. |
doctor, report, readiness | report article12, readiness lifecycle/fork-defense/quorum/assurance/connectors/local-vault/nova/production | Run install diagnostics, deterministic Article 12 reporting, and release-readiness evidence checks. |
cd sdk/go
go run ./cmd/attesto --json version
go run ./cmd/attesto --json \
--api-key-env ATTESTO_API_KEY \
streams create \
--use-case ai-decision-history \
--policy-id policy-2026-01
Offline receipt verification:
go run ./cmd/attesto --json receipts verify \
--file receipt.json \
--public-key-hex "$ATTESTO_RECEIPT_SIGNER_PUBLIC_KEY_HEX"
Production readiness evidence check:
go run ./cmd/attesto --json readiness lifecycle
go run ./cmd/attesto --json readiness fork-defense
go run ./cmd/attesto --json readiness production
Marketplace publisher automation:
go run ./cmd/attesto --json marketplace init \
--output attesto.connector.json \
--slug signed-webhook-evidence \
--name "Generic Signed Webhook Evidence" \
--version 1.0.0 \
--category compliance \
--summary "Produces Attesto evidence for signed webhook events." \
--description "Produces verifiable Proofstream events for signed webhook payloads." \
--publisher-slug attesto \
--publisher-name Attesto \
--repository-url https://git.rotz.ai/attesto/attesto-v1/src/branch/attesto-2.0/connectors/webhook \
--docs-url https://docs.attesto.eu/manuals/connectors.html#signed \
--provider-url https://docs.attesto.eu/manuals/connectors.html#signed \
--auth-mode signed-webhook \
--auth-scopes webhook:read \
--sync-modes webhook \
--event-types webhook.event.received \
--canary-ref release/attesto-2.0-connector-assurance-readiness/result.json \
--capabilities proofstream,offline-verification
go run ./cmd/attesto --json marketplace validate \
--manifest-file attesto.connector.json
go run ./cmd/attesto --json \
--token-env ATTESTO_TENANT_TOKEN \
marketplace submit \
--manifest-file attesto.connector.json \
--source-ref https://git.rotz.ai/attesto/attesto-v1/src/branch/attesto-2.0/connectors/webhook \
--visibility public \
--pricing-model free
Operator endpoints
Tenant/operator endpoints require bearer-token mode. Use this only in trusted operator automation and never in public clients.
from attesto import AttestoV2Client
operator = AttestoV2Client.with_bearer_token(
os.environ["ATTESTO_TENANT_TOKEN"],
)
streams = operator.list_tenant_streams()
forks = operator.list_fork_evidence(streams[0]["streamId"])
const operator = new AttestoV2Client({
apiKey: process.env.ATTESTO_TENANT_TOKEN!,
authMode: "bearer",
});
const streams = await operator.listTenantStreams();
const forks = await operator.listForkEvidence(String(streams[0].streamId));
operator, err := attesto.NewBearerClient(os.Getenv("ATTESTO_TENANT_TOKEN"))
if err != nil { log.Fatal(err) }
streams, err := operator.ListTenantStreams(context.Background(), "", 100, 0)
if err != nil { log.Fatal(err) }
Offline and online verify helpers
SDK verification methods are useful in services that receive Attesto receipts or bundles and need to fail closed before accepting them.
from attesto import AttestoV2Client
from datetime import UTC, datetime
import os
with AttestoV2Client(api_key=os.environ["ATTESTO_API_KEY"]) as attesto:
report = attesto.verify_object(
kind="bundle",
proof_object=bundle_object,
)
if not report.ok:
raise RuntimeError(report.problems)
const report = await attesto.verifyObject({
kind: "bundle",
object: bundleObject,
});
if (!report.ok) {
throw new Error(report.problems.join("; "));
}
Provenance verification (Attesto 3)
The 0.5.0 SDKs add a verification client for the
Attesto 3 provenance lane: commitment-only provenance streams fed by
a customer-controlled Local Vault. The vault's pinned Rust edge core
builds capsules, commitments and signatures; the SDK re-derives and
checks them and deliberately cannot construct a capsule or a
randomizer. Every function in this section runs offline, with no
call to Attesto, and every report carries a not_claimed
list that a verifier screen must render next to the result.
Protocols: ATTESTO-PROVENANCE-001,
ATTESTO-DISCLOSURE-001, ATTESTO-ZK-RANGE-001
and the bundle provenance binding of
ATTESTO-PROOFSTREAM-001. Conformance is pinned by the
shared golden-vector corpus in all three languages.
| Verifier | Python (attesto.provenance) | TypeScript (@attesto/sdk) | Go (go.attesto.eu/sdk) |
|---|---|---|---|
| Disclosure presentation | verify_disclosure | verifyDisclosure | VerifyDisclosure |
| Bundle provenance inclusion + key revocation | verify_bundle_provenance, evaluate_key_revocation | verifyBundleProvenance, evaluateKeyRevocation | VerifyBundleProvenance, EvaluateKeyRevocation |
| Effective assurance | effective_assurance | effectiveAssurance | EffectiveAssurance |
| Exact private-numeric opening | verify_pedersen_opening (attesto[zk]) | verifyPedersenOpening (@noble/curves peer) | zk.VerifyOpening (go.attesto.eu/sdk/zk) |
| ZK range result | inspect_predicate_result, validate_range_statement | inspectPredicateResult, validateRangeStatement | InspectPredicateResult, ValidateRangeStatement |
Verify a disclosure presentation offline
A holder's Local Vault issues a selective-disclosure presentation:
the revealed leaves with their randomizers, two-hop inclusion proofs
to the capsule root, and an Ed25519 signature by the issuing
installation. The verifier opens each revealed commitment and
replays each proof to the presented capsule_root.
Problems are collected, not raised, so the caller sees everything
that is wrong. Pass the nonce you issued for challenge mode;
without it the presentation is bounded only by its
expires_at and the report says
bounded_lifetime rather than implying a freshness it did
not check. Non-claim: the disclosure proves the revealed leaves are in
the capsule; it is not a statement that the capsule holds nothing
else.
from attesto.provenance import verify_disclosure
report = verify_disclosure(
presentation,
expected_nonce=challenge,
subject_commitment=asset_commitment,
)
report.ok # every leaf opened and every proof folded to capsule_root
report.verified_leaves # ({"subtree": "claims", "leaf_role": "c2pa_manifest_valid", "value": ...},)
report.freshness # "challenge" | "bounded_lifetime"
report.subject_checked # True only when subject_commitment matched
report.problems # () or every problem found
report.not_claimed # ({"id": "undisclosed_facts_absent", "statement": ...},)
import { verifyDisclosure } from "@attesto/sdk";
const report = await verifyDisclosure(presentation, {
expectedNonce: challenge,
subjectCommitment: assetCommitment,
});
report.ok; report.verified_leaves; report.freshness;
report.subject_checked; report.problems; report.not_claimed;
report := attesto.VerifyDisclosure(presentation,
attesto.WithExpectedNonce(challenge),
attesto.WithSubjectCommitment(assetCommitment),
)
report.Ok; report.VerifiedLeaves; report.Freshness
report.SubjectChecked; report.Problems; report.NotClaimed
Verify bundle provenance inclusion and key revocation offline
A verifier bundle over a provenance stream carries
provenance_root, provenance_event_count and
vault_key_lifecycle inside its hashed payload. An
inclusion object, returned by
GET /v2/streams/{streamId}/provenance-events/{sourceRef}/bundle-inclusion?from_checkpoint_id=...&to_checkpoint_id=...
or carried as provenance_inclusions next to the bundle,
proves one capsule root under that root. The verifier recomputes the
bundle hash, re-hashes the leaf from its fields, replays the proof,
takes the receipt time for the leaf's seq_no from the
bundle's own receipts, and applies the frozen revocation rule to the
installation the leaf names. inclusion and
key_status stay separate: a capsule root can be provably
under the bundle while its key was revoked before receipt, and
not_evaluated is never a pass. Revocation is evaluated
against the platform receipt time, never the vault-claimed
occurred_at, with an inclusive boundary; a claim that
predates the revocation is flagged suspect_backdated.
Non-claims: the root proves the capsule root existed under the bundle
and nothing about the capsule's contents; the key lifecycle is as of
bundle build, so a later revocation is not in the bundle.
from attesto.provenance import evaluate_key_revocation, verify_bundle_provenance
report = verify_bundle_provenance(bundle, inclusion)
report.ok # bundle hash holds, inclusion VALID, key live at receipt
report.inclusion # "VALID" | "INVALID"
report.key_status # "valid" | "revoked_at_receipt" | "unknown_installation" | "not_evaluated"
report.flags # e.g. ("revoked_at_receipt", "suspect_backdated")
report.not_claimed # three statements
verdict = evaluate_key_revocation(
revoked_at=key_status["revokedAt"], # None when never revoked
receipt_time=receipt["payload"]["issued_at"],
claimed_occurred_at=envelope["occurred_at"],
reason=key_status["revocationReason"],
)
verdict.accepted # status == "valid"
import { evaluateKeyRevocation, verifyBundleProvenance } from "@attesto/sdk";
const report = await verifyBundleProvenance(bundle, inclusion);
report.ok; report.inclusion; report.key_status; report.flags; report.not_claimed;
const verdict = evaluateKeyRevocation(
keyStatus.revokedAt,
receipt.payload.issued_at,
envelope.occurred_at,
keyStatus.revocationReason,
);
verdict.accepted;
report := attesto.VerifyBundleProvenance(bundle, inclusion)
report.Ok; report.Inclusion; report.KeyStatus; report.Flags; report.NotClaimed
verdict := attesto.EvaluateKeyRevocation(revokedAt, receiptTime, claimedOccurredAt, reason)
verdict.Accepted()
Derive effective assurance (L3 is derived, never signed)
A vault signs L0 (software-held key), L1
(key in a non-extractable PKCS#11 token) or L2 (L1 plus
a TPM 2.0 quote over the vault's measurement) in its envelope, and
the platform refuses an L1/L2 envelope it cannot substantiate from a
registered attestation. L3 has no on-wire
representation: the verifier derives it from L2 plus a
met witness quorum on the containing checkpoint, and an envelope
claiming L3 is refused. Anchor state is reported alongside and never
promotes a level. The report keeps vault assurance, witness quorum,
anchor state and the derived level as four separate facts. How the
levels are earned is described in the
Local Vault guide.
from attesto.provenance import effective_assurance
report = effective_assurance("L2", witness_quorum_met=True, anchor_confirmed=True)
report.effective # "L3"
report.derived # True: derived here, signed by nobody
report.reasons # ("anchor confirmed; anchoring does not promote assurance", "L3 derived from L2 plus a met witness quorum")
effective_assurance("L2").effective # "L2": quorum not evaluated withholds L3
effective_assurance("L3") # raises AttestoProvenanceError
import { effectiveAssurance } from "@attesto/sdk";
const report = effectiveAssurance("L2", { witnessQuorumMet: true, anchorConfirmed: true });
report.effective; // "L3"
report.derived; // true
report.reasons;
met := true
report, err := attesto.EffectiveAssurance("L2", &met, &met)
report.Effective // "L3"
report.Derived // true
report.Reasons
Verify an exact private-numeric opening
A private numeric claim commits its encoded value as a Pedersen
commitment over ristretto255. When a holder reveals the value and
the blinding, the verifier recomputes the commitment and compares it
byte for byte. Curve arithmetic is optional because the rest of
verification is SHA-256 and Merkle work: Python needs
attesto[zk], TypeScript the @noble/curves
peer dependency, and Go the separate go.attesto.eu/sdk/zk
module. A client without it reports not_checked. The
descriptor must already have opened its claim leaf under the capsule
root, otherwise a matching pair can be fabricated whole. A value of
exactly zero is a legal opening. This does not verify a range proof.
from attesto.provenance import pedersen_available, verify_pedersen_opening
opened = (
verify_pedersen_opening(descriptor, encoded_value, blinding_scalar)
if pedersen_available()
else None # report "not_checked"
)
import { pedersenAvailable, verifyPedersenOpening } from "@attesto/sdk";
const opened = (await pedersenAvailable())
? await verifyPedersenOpening(descriptor, encodedValue, blindingScalar)
: null; // report "not_checked"
import "go.attesto.eu/sdk/zk"
opened, err := zk.VerifyOpening(descriptor, encodedValue, blindingScalar)
Inspect a ZK range result
Selective disclosure v2 proves that a named detector's measurement
fell inside an interval without revealing it. No SDK verifies the
range proof itself; that remains the Rust core's job. The SDK reports
zk_predicate: not_checked under
verified_here, keeps what the issuer claimed under
reported_by_issuer, and refuses a result that drops one
of the three required non-claims or carries a verdict-shaped field
such as authentic, score or
probability. A proven bound says nothing about whether
the content is machine-generated. Capsule evidence from an
AttestoMark Image, Audio or Video provider is an
ATTESTO-PROVIDER-RESULT-001/0.2 object whose
presented_matches_record field reports whether the
bytes presented were the exact asset that was marked; a mismatch is
an observation an honest transcode also produces, never a refusal.
from attesto.provenance import inspect_predicate_result, validate_range_statement
report = inspect_predicate_result(result)
report["verified_here"] # {"zk_predicate": "not_checked", "capsule_inclusion": "not_checked"}
report["reported_by_issuer"]
report["not_claimed"] # detector_correctness_not_proven, content_truth_not_proven, ai_generation_not_proven
width = validate_range_statement(statement) # 8 | 16 | 32 | 64
import { inspectPredicateResult, validateRangeStatement } from "@attesto/sdk";
const report = inspectPredicateResult(result);
report.verified_here; report.reported_by_issuer; report.not_claimed;
const width = validateRangeStatement(statement);
report, err := attesto.InspectPredicateResult(result, nil)
report.VerifiedHere; report.ReportedByIssuer; report.NotClaimed
width, err := attesto.ValidateRangeStatement(statement)
Not in the SDKs: capsule construction, randomizer generation and
envelope signing live in the Local Vault's edge core; range proofs
are verified only by the Rust core; there is no client wrapper yet
for POST /v2/provenance/streams; and the
attesto CLI does not verify disclosures or bundle
provenance in 0.5.0.
MockAttesto for local tests
attesto.testing.MockAttesto is a Python test harness for
local CI and integration tests. It uses the same canonical hashing and
receipt shapes as the SDK, but signs with a per-instance throwaway
mock key and marks objects as mock evidence. Use it to test your
application flow without network access or an Attesto account; do not
use mock receipts in production evidence or customer bundles.
MockAttesto is intentionally fail-closed against real trust roots: verification with a production witness key must reject mock evidence. That keeps tests fast without creating a path for synthetic evidence to pass as production proof.
Companion packages and edge surfaces
The core SDKs stay small. Separate packages cover edge relay, MCP tooling, workflow nodes, and the future independent witness node. These packages must never become hidden transitive dependencies of the core SDKs.
| Surface | Package | Use | Status rule |
|---|---|---|---|
| MCP server | attesto-mcp | Expose deterministic Attesto tools to MCP hosts. | Install only from PyPI release evidence. |
| Local Vault | attesto-local-vault | Customer-edge encrypted spool, relay, and optional witness mode. | Keys stay local; no frontend use. |
| n8n node | n8n-nodes-attesto | Workflow receipts and signed webhook verification. | Credentials stay in n8n credentials. |
| Independent witness node | attesto-witness, @attesto/witness, go.attesto.eu/witness | Privacy-preserving observation of public or explicitly shared heads. | Phase-gated; not a core SDK dependency. |
pip install attesto-mcp
pipx install attesto-local-vault
npm install n8n-nodes-attesto
Specified as a privacy-preserving observation node package. Current customer-operated witness behavior is available through Local Vault witness mode; standalone attesto-witness, @attesto/witness, and go.attesto.eu/witness should be installed only after release evidence marks that package green.
Security rules
- Use SDKs from server-side code only.
- Store system keys in your secret manager and inject them at runtime.
- Do not place system keys in frontend bundles, mobile apps, query strings, or logs.
- Use the default production origin unless your tenant has a private deployment origin.
- Keep idempotency enabled for every write path.
