SDK docs · sdk/02

Python SDK (embedded mode)

The embedded Python SDK: one call returns the decision, five ports take your infrastructure, and the proof engine ships compiled in at a fixed version.

Install

Install. From PyPI (a prebuilt wheel for Linux x86-64; elsewhere pip builds the source distribution, which needs a Rust toolchain), or from a clone of the main project, https://gitlab.com/mintid/mintid (verifier-core/, Apache License 2.0).

The pin is the only thing that says which engine you got. build_info() reports it at runtime, with the store-layout vectors, spec revision and suite version. The engine is real and in production; an independent audit of its implementation is scheduled and its findings will be published — see protocol state. To exercise it against a live chain, use the public testnet or the local stack of the same project; the single-node production chain is not a place to test.

The public surface

mintid-verifier-sdk is the embedded mode: your Python backend imports it and gets each decision in-process. The proof engine ships compiled inside the package at a version fixed at build time, so a supported installation cannot end up with a substituted or mismatched engine.

The public surface is small and frozen: one decision entrypoint, the challenge types that mirror the service contract, the closed reason-code vocabulary and five infrastructure ports. Everything else is internal and may change without notice.

A test enforces that surface on every change, and versions follow semver: any change to the surface, or to what the SDK accepts, is a major version.

The entrypoint

validate_presentation takes the challenge you issued and the holder’s response, and returns a decision. You supply infrastructure, never policy:

PortWhat it providesYour freedom
Chain readerproven reads from chain nodes you choose, checked against your trust anchorwhich nodes — never whether reads are proven
Replay storedurable, exactly-once consumption of challenges; a durable store ships with the SDKthe backend, as long as consumption stays atomic and exactly-once
Proof enginethe engine built into the packagenone — a proof not bound to the exact challenge is always rejected
Decision logthe sink for decision recordswhere records go — never what they contain
Clockthe time you pass ina skewed clock only makes you more rejecting

How far behind the latest chain height a challenge may be is a local deployment setting, never a per-request option.

Issuing challenges

A challenge carries exactly what the service contract describes: a session identifier and a single-use value generated on your side, your verifier identity, one of your registered exact origins, your registered request key, an expiry of exactly ten seconds, the finalised chain height you read, and the issuer and claim policies you require.

It is serialised canonically and signed with your registered request key. The proof binds to the whole canonical body, so tampering with any part of the challenge breaks the binding (the fifth of the nine acceptance conditions listed on the integration overview).

Chain access

Trust is split into two roles on purpose:

  • Any chain node may answer queries, and is assumed malicious: every answer must carry a store proof.
  • The trust anchor is separate: headers come from a source you control — typically your own node — and never from an arbitrary public endpoint. A light client that checks untrusted peers is planned and has not shipped; until it does, back the anchor with a node you run.

Absence is never trusted: if a node claims a record does not exist and cannot prove it, the read fails closed and the decision is state_unproven.

Retention (what you keep, all of it)

Exactly one decision record per decision, accept or reject: the session identifier, whether it was accepted, the reason code, a digest of the bound context and the time of the decision. Nothing else fits — presentations, proof bytes and claim values are never persisted — and any extension of that record is a privacy review.