The verification path described here is a standalone extract of the engine’s own acceptance rule. Third-party verifiers run byte-identical code to the engine before it acts on a UDID, so a receipt that verifies for you would also verify for the engine.
What @ixo/udid-verify is
@ixo/udid-verify is a publishable npm package (Apache-2.0) that verifies UDID receipts — the signed determinations issued by the IXO Evals Engine when a claim-evaluation workflow reaches a decision point.
A UDID receipt is a compact JWS (EdDSA / Ed25519, algorithm-pinned) over the canonical JSON encoding of a determination payload (iss, aud, sub, jti, act, res, optional out). Verifying one correctly means more than checking the signature. The package ships:
EdDSA-pinned compact-JWS verification withkidselection.- A verification-only
VerifierKeyringbuilt from the publicGET /v1/issuer-keysresponse (kids are recomputed from key bytes and rejected on mismatch — fail-closed). - Canonical-JSON helpers (deep key-sorted
canonicalJsonString) and CID helpers (cidV1RawSha256,cidV1RawSha256Utf8). - Bundled copies of the normative UDID payload schemas.
outbinding / consistency checks (theoutnarrative is descriptive only;resis the trusted decision surface).fetchIssuerKeysandparseIssuerKeysResponsefor issuer-key discovery.- A one-call
verifyUdidReceiptthat applies the engine’s full acceptance rule and returns a list of named failures.
Who should use it
Reach for@ixo/udid-verify when your service consumes UDID receipts but is not the engine that issued them.
Bridges and workers
Bridges and workers
An
ixo-bridge or worker that gates on-chain submissions on a valid UDID should reject anything that fails the same acceptance rule as the engine.Oracle-to-oracle trust
Oracle-to-oracle trust
An Agentic Oracle consuming another oracle’s determination should verify the receipt end-to-end before treating
res as trustworthy.Third-party integrators
Third-party integrators
Registries, dashboards, or downstream services that show or act on determinations should verify receipts locally so the decision surface can be inspected without trusting an intermediate transport.
udid-validator package instead — it keeps the issuer-side helpers (secret-to-key derivation, signing IssuerKeyring) and delegates verification to @ixo/udid-verify so both sides run identical code.
Install
One-call verification
For the common case — you have a compact JWS and know the engine that issued it — pass the engine’s base URL and the audience the receipt must be addressed to:verifyUdidReceipt resolves the issuer’s public keys from GET /v1/issuer-keys on the supplied base URL, verifies the compact JWS with kid-selected key material, and applies the engine’s full acceptance rule. Canonical-byte enforcement is always on: a receipt whose signed bytes are not the canonical encoding of its payload is not a UDID the engine issued.
Bring your own keys
If the keys are pinned, cached, or resolved out-of-band, pass a raw published-keys array or a pre-builtVerifierKeyring:
VerifierKeyring.fromPublishedKeys holds no private material. It maps each JWS header kid to an Ed25519 public KeyObject, so historically issued UDIDs keep verifying across signing-key rotations. Every listed key is checked: kid is recomputed from the raw public key bytes and a mismatch is rejected. An unknown or missing kid fails closed as unknown_kid.
Fetch issuer keys manually
If you want to cache the response, share it across verifications, or apply custom TLS or retry behavior, usefetchIssuerKeys (or parseIssuerKeysResponse when you already have the body):
GET /v1/issuer-keys route needs no auth token and is cacheable (cache-control: public, max-age=300). Your trust root is the TLS connection to the deployment you already trust to have evaluated the claim. Pin the keys if you need to remove that runtime dependency.
The acceptance rule
Only trustreport.payload after every check passes. verificationReportFailures(report) returns an empty array exactly when the receipt is trustworthy — the same acceptance rule the engine applies before submitting a determination on-chain, and the same one bridges and workers should apply before acting.
The named failures mirror the engine’s own gates:
Additional low-level errors — for example
unknown_kid when the JWS header refers to a kid not in the keyring — surface on report.errors.
out is descriptive, res is the decision surface
The optional out block in a UDID payload is a human-readable narrative. It should not be treated as the trusted decision. The package exposes helpers to check that out stays consistent with res — for example, that a summary does not contradict the outcome or claim settlement authority it does not have:
report.payload.res — never from out.
Also included
canonicalJsonString/sortKeysDeep— the signing canonicalization.cidV1RawSha256/cidV1RawSha256Utf8— the engine’s content-proof convention (CIDv1,rawcodec, sha2-256, base32) for traces, evidence, and rubric bindings.validateUdidPayloadSchema— standalone payload schema validation.verificationReportMatchesCompactJws— bind a verification report back to the exact compact bytes it was produced from.issuerKid/issuerPublicKeyFromRaw— recompute akidfrom raw Ed25519 public key bytes.
Related docs
Claim evaluation protocol
The architecture behind Claims, evidence, rubrics, and UDID determinations.
Agent evaluations
Design Qi evaluation workflows that issue UDID records.
Agentic Oracles
Learn how oracle services fit into the IXO stack.
Claims management
Build Claim workflows and record evaluations.