Registry Notary ships a typed Rust client plus Python and Node.js wrappers. Use
these clients instead of hand-written HTTP calls when application code needs the
Notary wire contract, purpose handling, bounded response reads, route-aware
retry behavior, JWKS refresh behavior, and redacted error mapping.
The Rust crate is the source of truth. Python and Node expose the main
application, discovery, OID4VCI, and federation helpers, but keep JSON as
dictionaries or plain objects. Rust additionally exposes operational, admin,
format, and explicit SD-JWT VC verifier helpers.
Use the service root URL. A path prefix is allowed and is preserved when routes
are joined.
Clients require HTTPS for non-loopback hosts. Rust allows HTTP loopback only in
debug or test-support builds. Python and Node local workflows may use
http://127.0.0.1, http://localhost, or http://[::1].
Python also exposes an explicit lab/internal escape hatch for Docker Compose
and private service-network deployments:
allow_insecure_internal_http=True. Use it only when transport is already
protected by the deployment boundary or a local development network. Production
service URLs should remain HTTPS.
The credential behind your auth mode carries a scopes list, and every claim
declares a required_scope on its source bindings that is enforced before
evaluation. Scope strings are operator-defined <namespace>:<operation> values
(for example civil_registry:evidence_verification or
registry_notary:credential_issue); there is no fixed global registry of scope
names. When you connect to a deployment you do not operate, ask the operator
which scopes the claims you need require and request a credential carrying
exactly those scopes. GET /v1/claims (list_claims in every SDK) confirms
which claims your credential can see before the first evaluation; a 403 on
evaluation means the credential lacks that claim’s required_scope.
Evaluation routes can carry a data purpose in the Data-Purpose header and in
the request body purpose field. If both are present, they must match exactly.
The client rejects mismatches before sending the request.
Set a client default purpose when most calls share one purpose. Override per
call through request options when needed.
Retries are disabled by default. When enabled, they are still route-aware:
GET routes may retry transport errors, 429, or 503 according to the policy.
POST /v1/batch-evaluations may retry only when an Idempotency-Key is
supplied.
Evaluation, render, credential issuance, OID4VCI credential, and federation
submission are never retried because those POST routes are not deduplicated by
the server.
Retry-After seconds are honored. Rust, Python, and Node also handle HTTP-date
Retry-After by using the response Date header as the reference clock when it
is present.
Rust returns NotaryClientError. Python and Node expose:
NotaryError
NotaryTransportError
NotaryProblemError
Safe fields for logs are status, code, title, retryable, and request_id. Do not
log raw request bodies, requester or target identifiers, holder proofs,
credential bodies, SD-JWT disclosures, nonces, Authorization, X-Api-Key, or
Problem Details detail.
The Rust portable() error envelope is intended for language bindings and FFI.
It intentionally excludes sensitive detail strings.
Note: the path = "crates/..." dependencies below assume you are building
inside the Registry Notary workspace checkout. The workspace crates are not
published to crates.io. An external integrator without the checkout should
use a git dependency pinned to a release tag (for example v0.3.1) or a
commit:
[dependencies]
registry-notary-client = { git = "https://github.com/jeremi/registry-notary", tag = "vX.Y.Z" }
registry-notary-core = { git = "https://github.com/jeremi/registry-notary", tag = "vX.Y.Z" }
Evaluation requests use the canonical requester/target evidence model. The
target is the entity being evaluated; optional requester context identifies the
actor or represented party, and relationship explains why the requester may ask
about that target.
Note: the raw-DTO examples construct registry-notary-core types directly and
assume building inside the workspace checkout. Integrators who only consume the
client over HTTP can use the high-level builder or JSON facade shown elsewhere
in this guide.
The render route carries evaluation_id in the path. Rust accepts the core
RenderRequest DTO and moves evaluation_id into
/v1/evaluations/{evaluation_id}/render before sending the body. Python and
Node raw helpers accept canonical snake_case JSON, require a mapping/object,
extract evaluation_id, and send the remaining fields as the route body.
use registry_notary_core::{CredentialIssueRequest, RenderRequest};
Enable the Rust verifier feature when relying-party or wallet code needs to
verify SD-JWT VC credential material. Verification is explicit and opt-in:
transport methods continue to return decoded response bodies without hidden
network refreshes or trust-policy decisions.
registry-notary-client = {
path = "crates/registry-notary-client",
features = ["verifier"]
}
use registry_notary_client::{HolderBindingPolicy, VerifyOptions};
The verifier resolves the JWS kid only from trusted issuer JWKS, reuses the
client’s short JWKS TTL cache, and forces one refresh on key.unknown. It does
not loop indefinitely. VerifyOptions lets callers set expected issuer,
accepted algorithms, expected vct, clock skew, and holder-binding policy.
Selective-disclosure presentations may include a subset of disclosures; each
presented disclosure must hash to a digest in the credential. When a
presentation includes a key-binding JWT, the verifier separates it from
disclosures and verifies its holder proof signature against the credential
cnf.jwk.
Verifier errors are redacted and safe for policy mapping by code. Stable codes
include signature.invalid, key.unknown, algorithm.disallowed,
claim.issuer_mismatch, claim.vct_mismatch, claim.time_invalid,
disclosure.digest_mismatch, holder_binding.required, and
holder_binding.kid_mismatch, and holder_binding.proof_invalid.
Python and Node do not expose verifier wrappers in this first phase. Callers in
those runtimes should use the Rust verifier through their application boundary
or perform verification in wallet-specific code.
bindings/python/registry_notary is the supported Python client package for
downstream applications. Its public names for application integrations are:
RegistryNotaryClient, RetryPolicy, evaluate,
evaluate_request, batch_evaluate_request, list_claims, get_claim,
issuer_jwks, raw_issuer_jwks, render_request,
issue_credential_request, and credential_status.
For citizen self-attestation, omit identity fields and let the server derive the
requester, target, and self relationship from the verified token binding:
Claim references may be plain strings or pinned objects with id and
version. The same versioned claim reference shape is supported for single
evaluation and batch evaluation.
Async evaluation helpers are prefixed with a, for example aevaluate and
aevaluate_request.
Raw render requests use canonical snake_case JSON and must include
evaluation_id. The Python wrapper rejects non-mapping inputs before it reads
or sends any fields.
The package is not currently published to the npm registry. With pnpm you can
install it directly from the git repository pinned to a release tag or commit
(for example v0.3.1):
Render uses the route-shaped API. renderRequest requires a plain request
object with snake_case evaluation_id, removes evaluation_id from the JSON
body, and posts the rest to /v1/evaluations/{evaluation_id}/render.