nexart.iodocs

    Verification

    How to verify any NexArt record, with or without API access.

    All verification results derive from this model.

    NexArt Integration (Canonical Flow)

    Flow:

    1. Capture execution input
    2. Seal locally (offline)
    3. Verify locally
    4. (Optional) Certify via node
    5. Verify again

    Verification outcomes:

    • Sealed → Integrity: PASS, Receipt: SKIPPED, Envelope: SKIPPED
    • Certified → Integrity: PASS, Receipt: PASS, Envelope: PASS

    Rules:

    • Sealing does NOT require a node
    • Certification is OPTIONAL
    • Verification does NOT require trust
    • SKIPPED is expected for local artifacts and is NOT a failure

    Do NOT:

    • call the node before sealing
    • recompute hashes manually
    • modify bundles after sealing
    • treat SKIPPED as failure

    Technical truth

    What a CER is
    A Certified Execution Record (CER) is a canonical, tamper-evident bundle representing one execution. It has bundleType: "cer.ai.execution.v1", a version, a createdAt ISO-8601 timestamp, a snapshot (model, inputHash, outputHash, metadata), and an optional context / contextSummary. The CER is identified by its certificateHash (SHA-256). Inputs and outputs are stored as hashes; raw payloads are not part of the bundle.
    Fields covered by certificateHash (whitelist)
    The hash is SHA-256 over a strict whitelist projection, canonicalized per the profile selected by protocolVersion (1.2.0nexart-v1, default; 1.3.0jcs-v1, RFC 8785, opt-in). Whitelist:bundleType, version, createdAt, snapshot, and (only when present) context, contextSummary, policyEvaluation. Any modification to a covered field changes the hash. Canonicalization is protocol-bound: verifiers MUST use the profile corresponding to the bundle's protocolVersion.
    Fields excluded from hashing
    The following are explicitly excluded from the hash payload and may be added, updated, or removed without invalidating the certificateHash: certificateHash itself, meta (including meta.attestation and the receipt), declaration, verificationEnvelope, verificationEnvelopeSignature, receipt, and any unknown fields not in the whitelist. Verifiers MUST apply the whitelist projection to the bundle as received; no reconstruction beyond the canonicalization profile bound to the bundle's protocolVersion.
    The three verification layers
    • certificateHash (integrity) — recompute SHA-256 over the JCS-canonicalized whitelist projection and compare with the bundle's certificateHash.
    • receipt signature (node attestation) — validate the Ed25519 receipt at meta.attestation using the node key matched by kid, and confirm it references the bundle's certificateHash.
    • verification envelope (full bundle signature, v0.16.1) — validate meta.verificationEnvelopeSignature against meta.verificationEnvelope. When absent, this layer returns SKIPPED.

    Each layer reports independently as PASS, FAIL, or SKIPPED. Verification statuses: VERIFIED, FAILED, NOT_FOUND.

    Independence model: local sealing, optional node certification, independent verification

    Local sealing — produced by the SDK (@nexart/ai-execution@1.0.0 via sealCer()) or the CLI (@nexart/cli@1.0.0 via nexart ai seal). Builds a canonical CER bundle and computes the certificateHash fully offline. No API key, no network call, no receipt, no verification envelope. The result is a sealed bundle: integrity only.

    Optional node certification — performed by the attestation node (POST /v1/cer/ai/certify / nexart ai certify). The node validates the bundle and issues an Ed25519-signed receipt (identified by kid) referencing the bundle's certificateHash, plus a verification envelope. Receipt and signatures are stored at bundle.meta.attestation and meta.verificationEnvelope. Certification adds attestation layers; it does not change the certificateHash. The result is a certified bundle.

    Independent verification — performed by anyone, with no trust in NexArt infrastructure required. Available via verify.nexart.io, the SDK, or the CLI. The bundle plus the node's published public keys are sufficient. For sealed bundles, only Layer 1 (integrity) is applicable; Layers 2 and 3 return SKIPPED. For certified bundles, all three layers return PASS.

    Mental model
    • Integrity ≠ Stamp ≠ Envelope.
    • Verification does not require trust.
    • Failure of one layer is not failure of all.
    What happens if verification fails
    Each verification layer fails for a different, specific reason. Isolating the failed layer tells you exactly what went wrong.
    LayerFailureMeaningAction
    Layer 1 — IntegritycertificateHash mismatchThe bundle was modified after sealing, or the wrong projection was hashed.Re-derive certificateHash with sealCer(...) over the strict whitelist. If it still differs, the stored bundle is no longer authentic.
    Layer 2 — Signed ReceiptReceipt signature invalidThe receipt was not produced by the published node key, or the receipt payload was modified.Refetch the node key set from /.well-known/nexart-node.json. If signature still fails, the receipt is not trustworthy.
    Layer 3 — Verification EnvelopeEnvelope signature invalid or projection mismatchThe envelope payload (5-field attestation projection) does not match what was signed, or the kid is wrong.Confirm the bundle includes meta.verificationEnvelope and meta.verificationEnvelopeSignature. Public/redacted payloads cannot satisfy Layer 3.
    NodeEXECUTION_MUTATION_DETECTED (409)An execution_id already maps to a different certificateHash. The node rejects mutation by design.Do not re-submit modified bundles under the same execution_id. Create a new execution.

    Local verification is not public verification.

    verifyCer() andverifyProjectBundle() prove integrity only. To make an artifact resolvable onverify.nexart.io, you MUST register it on the attestation node. See theEnd-to-End Verification Flow.

    How Verification Works

    Verification confirms the integrity and authenticity of a Certified Execution Record or Project Bundle. The canonical flow is:

    1. An execution happens.
    2. A CER is sealed locally (SDK sealCer() or CLI nexart ai seal), binding execution metadata to a deterministic certificateHash. This is fully offline.
    3. The sealed bundle can be verified immediately. Layer 1 (integrity) returns PASS; Layers 2 and 3 return SKIPPED because no node attestation is present.
    4. Optionally, the CER is certified by an attestation node, which adds a signed receipt and a verification envelope.
    5. A certified bundle can be verified against all three layers (PASS/PASS/PASS) and is resolvable at verify.nexart.io.
    6. Optionally, multiple CERs are collected into a Project Bundle with a projectHash.

    Sealed vs Certified

    PropertySealed (local)Certified (node)
    OriginSDK / CLI, fully offlineAttestation node (POST /v1/cer/ai/certify)
    API key requirednoyes (NEXART_API_KEY)
    certificateHashpresentpresent (identical input → identical hash)
    meta.attestation (receipt)absentpresent, Ed25519-signed
    meta.verificationEnvelopeabsentpresent (v0.16.1)
    Layer 1 — IntegrityPASSPASS
    Layer 2 — ReceiptSKIPPEDPASS
    Layer 3 — EnvelopeSKIPPEDPASS
    Third-party verifiableintegrity onlyyes (attested)

    SKIPPED is not a failure. A sealed bundle is a valid CER; it simply has not been attested by a node. Certification adds Layers 2 and 3 without changing thecertificateHash.

    The Three Verification Layers

    Verification is split into three independent layers. Each layer protects a distinct property and reports its result independently. Envelope failure MUST NOT be reported as integrity failure.

    Layer 1 — Integrity (certificateHash)

    Recomputes the certificateHash from the strict whitelist projection of the bundle, canonicalized per the profile selected by protocolVersion (1.2.0 → nexart-v1; 1.3.0 → jcs-v1 / RFC 8785). Proves the bundle has not been modified across covered fields.

    Hashed fields: bundleType, version, createdAt, snapshot, context (if present), contextSummary (if present).

    Not hashed: certificateHash, meta, declaration, verificationEnvelope, verificationEnvelopeSignature, receipt, any unknown fields.

    Layer 2 — Receipt (Node stamp)

    Validates the Ed25519 signed receipt over the certificateHash. Proves the node attested the bundle at a specific time. Receipt verification is independent of envelope verification.

    Layer 3 — Verification Envelope (v0.16.1, v2)

    Ed25519 signature over { attestation, bundle } using a strict whitelist projection. Proves full bundle integrity under the node's signature beyond the certificateHash.

    • Attestation projection (5 fields, exact): attestationId, attestedAt, kid, nodeRuntimeHash, protocolVersion.
    • Bundle projection: bundleType, version, createdAt, snapshot, context (if present), contextSummary (if present).
    • certificateHash is NOT part of the signed payload.
    • meta is NOT signed by the envelope.
    • receipt is NOT signed by the envelope.

    Envelope failure indicates the signed bundle projection has been altered. It is reported separately from Layer 1 and MUST NOT be conflated with integrity failure.

    Public verification limitation
    When using public endpoints, snapshot.input and snapshot.output are redacted. Therefore:
    • Full envelope verification is NOT possible from public data alone.
    • Receipt verification IS possible.
    • certificateHash verification IS possible (against the public-safe representation).

    Why Envelope Verification May Fail

    Envelope verification (Layer 3) is independent of integrity (Layer 1) and receipt (Layer 2). A bundle can be fully intact and properly attested while the envelope check returns FAIL or SKIPPED. The two outcomes carry different meaning and MUST NOT be conflated with integrity failure.

    SKIPPED vs FAIL

    • SKIPPED — the envelope check is not applicable. The bundle does not includemeta.verificationEnvelope and/or meta.verificationEnvelopeSignature, OR the verifier cannot reconstruct the signed projection (for example, fields required by the projection are not present in the received bundle). SKIPPED is NOT a failure.
    • FAIL — the envelope is present and reconstructable, but the Ed25519 signature does not validate against the projected payload using the node key matched bykid.

    Reasons Layer 3 returns FAIL while Layers 1 and 2 PASS

    1. Mutation of a signed-but-unhashed field. The envelope signs an attestation projection (attestationId, attestedAt, kid, nodeRuntimeHash, protocolVersion) that is NOT covered by certificateHash. Editing one of those fields breaks Layer 3 while Layer 1 still passes.
    2. Re-serialization that breaks canonicalization. Layer 3 requires the exact canonicalization profile bound to the bundle's protocolVersion(nexart-v1 for 1.2.0, jcs-v1 / RFC 8785 for 1.3.0). Tools that pretty-print, reorder keys, change number formatting, or alter Unicode escaping invalidate the signature even when content is semantically identical.
    3. Key mismatch (kid). The verifier resolves the public key by kid from node.nexart.io/.well-known/nexart-node.json. If the published key set has rotated or the kid is unknown, the signature cannot be validated.
    4. Partial / redacted bundle. Public-safe representations may strip fields from snapshot or omit attestation projection fields. The envelope payload cannot be reconstructed bit-for-bit, so Layer 3 returns SKIPPED (or FAIL if the verifier attempts strict reconstruction). See "Why public bundles cannot always verify the envelope" below.
    5. v0.16.0 signals payload alignment bug. Bundles created with@nexart/ai-execution@1.0.0 that include signals MAY fail envelope verification due to a payload alignment issue fixed in v0.16.1. Operators SHOULD re-certify affected executions via POST /v1/admin/recertify-batch.
    6. Pre-envelope artifact. Bundles produced before v0.16.1 may not include any envelope at all. Layer 3 returns SKIPPED by compatibility fallback. This is NOT a failure of integrity or attestation.

    Envelope FAIL does not imply Integrity FAIL

    Because certificateHash and the envelope cover different projections (the envelope additionally signs the attestation projection and excludes certificateHash itself), a Layer 3 FAIL with Layer 1 PASS indicates the bundle's hashed content is intact, but the node's signed surface around it has been altered. Verifiers MUST report each layer independently. The aggregate verification status follows the rules in Verification Statuses and Errors.

    Why public bundles cannot always verify the envelope

    The public verifier consumes a redacted representation of the record. Raw snapshot.input and snapshot.output are never exposed publicly; only their SHA-256 digests are. Some metadata fields may also be withheld depending on export settings. Because Layer 3 signs a strict whitelist projection that includes snapshot (and, when present, context / contextSummary), a verifier without the exact source bytes cannot reconstruct the signed payload byte-for-byte.

    In that case the public verifier returns SKIPPED for Layer 3 and still reports PASS for Layer 1 (against the public-safe representation) and Layer 2 (receipt validation against certificateHash). Full envelope verification requires the original, non-redacted CER bundle — typically held by the producer or an authorized auditor.

    What Verification Proves

    Verification answers up to four questions about a Certified Execution Record:

    1. Has the CER bundle been modified since it was created?
    2. Was the receipt signed by a valid NexArt attestation node?
    3. Does the receipt reference the correct certificateHash?
    4. Has the verification envelope been altered? (when present)

    If all applicable checks pass, the record is intact and its attestation is trustworthy. For a detailed breakdown, see AI CER Verification Layers.

    v0.16.0 → v0.16.1 compatibility
    Bundles created with @nexart/ai-execution@1.0.0 that include signals may fail envelope verification due to a payload alignment issue. v0.16.1 fixes this. Re-certification may be required. Operators can use POST /v1/admin/recertify-batch to re-seal affected executions.

    How to Verify a Record

    There are three ways to verify a CER through the public verifier at verify.nexart.io. Prefer certificateHash for any persisted reference — it is the canonical identity of the artifact. executionId is convenience metadata only.

    1. By Certificate Hash (canonical)

    If you have the certificateHash, use the hash-based URL. The colon in the hash must be URL-encoded:

    Verify by Certificate Hash
    https://verify.nexart.io/c/sha256%3A7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069

    2. By Execution ID (convenience only)

    executionId is a convenience identifier returned by the certify API. It MUST NOT be used as a primary key for storage or deduplication. Use it for ad-hoc lookup only:

    Verify by Execution ID
    https://verify.nexart.io/e/exec_abc123

    3. By Uploading a CER Bundle

    You can also verify a record by uploading or pasting the full CER JSON bundle at verify.nexart.io. The verifier will recompute the hash and check the signature locally.

    This is useful when you have the CER file but not the execution ID or verification URL.

    What Is Publicly Visible?

    The public verifier uses a redacted, public-safe representation of the record:

    • Verification status, certificateHash, timestamp, and node identity are visible.
    • Raw input and output content is never exposed. The record contains SHA-256 hashes of these fields, not the original text.
    • Metadata fields (like appId) may be included or redacted depending on the record's export settings.

    Anyone can verify that a record is intact and properly signed without seeing the private data that produced it.

    What Gets Stored for Public Verification?

    When a record is certified:

    • The attestation node returns a signed receipt containing the certificateHash, timestamp, node identity, and Ed25519 signature. This is stored at meta.attestation in the CER bundle.
    • A redacted, public-safe version of the record is persisted for verification.
    • Input and output content is hashed (SHA-256). The hashes appear in the record, but the original content is not stored by the node or verifier.
    • You control which metadata fields are included when you create the record.

    Verification Checks

    Each check returns PASS, FAIL, or SKIPPED:

    1. Bundle Integrity. Recompute the certificateHash from the bundle contents. If the hash differs, the bundle has been modified.
    2. Node Signature. Validate the Ed25519 signature using the public key published at node.nexart.io/.well-known/nexart-node.json, matched by the kid in the receipt. SKIPPED if no attestation is present.
    3. Receipt Consistency. Confirm the receipt at meta.attestation.receipt references the same certificateHash as the bundle and that the node identity matches. SKIPPED if no attestation is present.
    4. Verification Envelope. When present, validate meta.verificationEnvelopeSignature against meta.verificationEnvelope. This confirms the authoritative displayed verification surface has not been altered. SKIPPED if the bundle does not include a verification envelope.

    For a detailed breakdown of what each layer protects, see AI CER Verification Layers.

    Verification Statuses

    The verification status reflects the overall outcome, as defined by the CER Protocol:

    Verification Statuses
    VERIFIED      All applicable checks pass. The CER is intact and,
                  if attested, has a valid signed receipt.
    
    FAILED        One or more checks fail. The record may have been
                  modified or the signature does not match.
    
    NOT_FOUND     The requested execution record was not located.

    Reading Verification Results

    The verifier reports four distinct outcome classes. They are not all failures:

    • VERIFIED: all applicable checks pass.
    • VERIFIED (supplemental): core integrity passes, but supplemental context (e.g. signals outside the hash scope) is present. This is NOT a failure; supplemental fields are simply not cryptographically bound.
    • FAILED: one or more applicable checks fail.
    • NOT_FOUND: the artifact was never registered on the node. See End-to-End Verification.

    For the precise semantics of each result class, reseal handling, and the canonical role of certificateHash vs executionId, see Verification Semantics.

    Expected Outcomes by Bundle Type

    • cer.ai.execution.v1 (with attestation): all checks PASS → VERIFIED
    • cer.ai.execution.v1 (without attestation): bundleIntegrity PASS, attestation checks SKIPPED → VERIFIED
    • signed-redacted-reseal: redacted reseal returned by the public verifier; validated against the NEW resealed certificateHashVERIFIED
    • hash-only-timestamp: only certificateHash is attested → VERIFIED
    • legacy: older format, limited coverage → VERIFIED or FAILED depending on data

    Project Bundle Verification

    For multi-step workflows, verification covers the entire Project Bundle:

    • projectHash integrity: recomputed from canonical content using sha256-canonical-json
    • Per-step CER verification: each embedded CER's certificateHash is checked independently
    • Project-level node receipt: validated if present

    Use verifyProjectBundle() (Node) or verifyProjectBundleAsync() (browser) from the SDK, or verify at verify.nexart.io via /p/:projectHash.

    Independent Verification (No API Required)

    You can verify a CER without calling any NexArt API. No trust in NexArt infrastructure is required. All you need is the CER bundle (including meta.attestation) and access to the node's published keys:

    1. Recompute the certificateHash from the CER bundle (SHA-256 over the JCS-canonicalized whitelist projection)
    2. Compare it with the certificateHash in meta.attestation.receipt
    3. Fetch the node's public key from node.nexart.io/.well-known/nexart-node.json
    4. Find the key matching the receipt's kid
    5. Verify the Ed25519 signature over the receipt payload

    If all steps pass, you can trust the attestation independently of NexArt infrastructure. No account, API key, or network call to NexArt is required beyond fetching the node's public key. For a from-scratch implementation guide in any language, see External Verification.

    protocolVersion and Canonicalization

    Every attested bundle declares its canonicalization profile in meta.attestation.protocolVersion. Verifiers MUST select the profile by this field and MUST fail closed on unknown values.

    Supported profiles
    protocolVersion = "1.2.0"   profile = "nexart-v1"   default  (custom canonicalization)
    protocolVersion = "1.3.0"   profile = "jcs-v1"      opt-in   (RFC 8785, standards-based)

    Canonicalisation is protocol-bound. There is no universal default. Verifiers MUST use the canonicalisation corresponding to the bundle's protocolVersion or hash recomputation will fail. Do NOT assume RFC 8785 universally.

    1.2.0 → nexart-v1 is the current default canonicalization profile. All SDK and CLI calls produce 1.2.0 bundles unless the producer explicitly opts into a different version.

    1.3.0 → jcs-v1 is opt-in. It uses JSON Canonicalization Scheme (RFC 8785) for both hashing and signing, providing a published, standards-based deterministic byte representation. Producers select it via createSnapshot({ protocolVersion: "1.3.0" }) or the CLI flag --protocol-version 1.3.0.

    Both profiles are accepted indefinitely. Verifiers MUST support both to remain compliant.protocolVersion is part of the attestation projection signed by the verification envelope, so it cannot be silently retargeted to a different profile without breaking Layer 3.

    Fail-closed Behavior

    Verification MUST fail closed. Any condition where a verifier cannot determine the correct rule to apply is reported as FAILED, never silently passed. SKIPPED is reserved for layers that are not applicable to the bundle as received (for example, an unsigned sealed bundle has no Layer 2 to run).

    • Unknown protocolVersionFAILED.
    • Unknown bundleTypeFAILED.
    • Receipt kid not present in the published node key set → FAILED (Layer 2).
    • Envelope present but a required projection field is missing or cannot be canonicalized → FAILED (Layer 3).
    • Envelope absent → SKIPPED (Layer 3). Not a failure; the bundle simply does not carry that proof.

    What Verification Does NOT Guarantee

    A PASS result asserts exactly what the protocol attests, and nothing more. The following properties are explicitly out of scope:

    • Completeness. Verification does not prove that the bundle represents every step of a larger workflow. Whether all relevant executions were captured is an integration concern.
    • Semantic correctness. NexArt proves the bundle was produced as recorded. It does not assert that the model output was correct, appropriate, or compliant.
    • Trusted (third-party) timestamping. attestedAt is a node-issued timestamp, bound to the bundle's certificateHash by the receipt signature. It provides an ordering guarantee relative to other records signed by the same node; it is NOT independent proof of existence at that wall-clock time. An external TSA (e.g. RFC 3161 via DigiCert) MAY be integrated alongside the receipt without modifying existing records.
    • Public log inclusion. The current attestation log is node-internal. There is no public Merkle tree and no external witness at this protocol version. Verifiers MUST NOT infer transparency-log inclusion from a PASS result.
    • Deterministic replay. Recomputing the same model output from the same inputs is only meaningful in controlled environments (fixed model version, seed, temperature 0, deterministic decoding). NexArt attests the recorded I/O; it does not assert reproducibility of the upstream model.

    CLI Usage

    @nexart/cli@1.0.0 provides a verifier that runs offline against a CER bundle file. It fetches the node key set only when the bundle declares an attestation.

    Install
    npm install -g @nexart/cli@1.0.0
    Verify a bundle
    nexart ai verify ./cer.json
    Expected output — certified bundle
    certificateHash : sha256:7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069
    protocolVersion : 1.2.0  (profile: nexart-v1)
    Integrity (L1)  : PASS
    Receipt   (L2)  : PASS
    Envelope  (L3)  : PASS
    status          : VERIFIED
    Expected output — sealed (offline) bundle
    certificateHash : sha256:9f2b1c8e4a7d6f3b0c5e8a1d2f4b6c8e9a0d3f5b7c2e4a6d8f1b3c5e7a9d0f2b
    protocolVersion : 1.2.0  (profile: nexart-v1)
    Integrity (L1)  : PASS
    Receipt   (L2)  : SKIPPED  (no attestation present)
    Envelope  (L3)  : SKIPPED  (no envelope present)
    status          : VERIFIED
    Error handling
    exit 0   status = VERIFIED
    exit 1   status = FAILED      (any applicable layer failed)
    exit 2   status = NOT_FOUND   (referenced record could not be located)
    exit 3   usage error          (missing file, malformed JSON, unknown flag)
    
    Failures print a machine-readable JSON report to stderr:
      { "status": "FAILED", "checks": { "bundleIntegrity": "FAIL", ... }, "reason": "..." }
    Producing a 1.3.0 (JCS) bundle — opt-in
    # Default is 1.2.0 (nexart-v1). Opt into 1.3.0 (jcs-v1, RFC 8785):
    npx @nexart/cli@1.0.0 ai seal input.json --protocol-version 1.3.0 --out cer.json
    npx @nexart/cli@1.0.0 ai verify cer.json
    # --protocol-version overrides the producer default for this invocation only.
    # Verifiers select the canonicalization profile from the bundle's protocolVersion;
    # the flag does not change verification behavior.

    For the full verification contract, see the CER Protocol specification. For SDK functions, see AI Execution SDK (sync and async modes). For browser-specific usage, see Browser Verification.