nexart.iodocs

    From Execution to Public Verification

    The complete lifecycle from local integrity to node attestation to public verification. Three trust states, not interchangeable.

    The Full Lifecycle

    Every verifiable execution moves through the same seven stages. Skipping any stage between local verification and public verification breaks the trust chain.

    Lifecycle
    1. Execute AI step                     (your application)
    2. Create CER                          certifyDecision(...)
    3. (Optional) Attest CER on node       POST /api/attest
    4. Build Project Bundle                createProjectBundle({ steps: [...] })
    5. Verify locally                      verifyProjectBundle(bundle)
    6. Register bundle on node  REQUIRED   POST /v1/project-bundle/register
    7. Public verification                 verify.nexart.io/p/{projectHash}
    Trust chain
    Execution -> CER -> Bundle -> Local Verify -> Node Register -> Public Verify
                                      (integrity)   (trust anchor)   (independent witness)

    Three Levels of Verification

    NexArt provides three distinct verification levels. They answer different questions and are NOT interchangeable.

    Level 1 - Local SDK Verification (integrity)

    Proves the artifact has not been modified since it was produced.

    • verifyCer(bundle)
    • verifyProjectBundle(bundle)
    • verifyCerAsync / verifyProjectBundleAsync (browser)

    What it proves: Bundle integrity. The recomputedcertificateHash /projectHash matches the bundle.

    What it does NOT prove: That any third party has witnessed the artifact. Local-only artifacts cannot be looked up onverify.nexart.io.

    Level 2 - Node Certification / Registration (trust anchor)

    Submits the artifact to the attestation node, which signs a receipt and writes the artifact to its proof tables.

    • POST /api/attest - attest a single CER
    • POST /v1/project-bundle/register - register a Project Bundle

    What it produces: An Ed25519-signed receipt anchored to the node's public key, plus a durable proof record on the node. This is what anchors trust.

    Level 3 - Public Verification (independent witness)

    Anyone can verify a node-registered artifact without your API key.

    • https://verify.nexart.io/c/{certificateHash} - single CER
    • https://verify.nexart.io/p/{projectHash} - Project Bundle

    Requires: A node-registered artifact. If the artifact was only verified locally, the public verifier returnsNOT_FOUND.

    Project Bundle Registration (REQUIRED for public verify)

    This is the step most often missed. Local verification is not a substitute for registration.

    Endpoint
    POST https://node.nexart.io/v1/project-bundle/register
    Authorization: Bearer <NEXART_API_KEY>
    Content-Type: application/json
    
    <full cer.project.bundle.v1 JSON returned by createProjectBundle()>

    Response

    A successful response includes:

    • attestationId - node-assigned identifier for the registered bundle
    • verificationEnvelope - canonical envelope covering the project-level receipt
    • signature - Ed25519 signature over the envelope by the node's signing key
    • metadata - node identity, key id, timestamp, protocol version

    Success Definition

    Registration is successful ONLY when ALL of the following are true:

    1. The node returns a 2xx response with the fields above.
    2. The bundle is written to the node's proof tables.
    3. https://verify.nexart.io/p/{projectHash} resolves and returns VERIFIED.

    A 200 response alone is not sufficient evidence of success. Always confirm against the public verifier.

    Minimal Correct Flow

    End-to-end (Node / TypeScript)
    import {
      certifyDecision,
      createProjectBundle,
      verifyProjectBundle,
    } from "@nexart/ai-execution";
    
    // 1. Generate CERs for each step
    const cer1 = await certifyDecision({ /* step 1 */ });
    const cer2 = await certifyDecision({ /* step 2 */ });
    const cer3 = await certifyDecision({ /* step 3 */ });
    
    // 2. Build the Project Bundle
    const bundle = createProjectBundle({
      projectTitle: "Contract review pipeline",
      steps: [cer1, cer2, cer3],
    });
    
    // 3. Local integrity check (does NOT make it publicly verifiable)
    const local = verifyProjectBundle(bundle);
    if (local.status !== "VERIFIED") {
      throw new Error("Local verification failed");
    }
    
    // 4. REQUIRED: register the bundle on the attestation node.
    // Without this step, the bundle will NOT resolve on verify.nexart.io.
    const res = await fetch("https://node.nexart.io/v1/project-bundle/register", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.NEXART_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(bundle),
    });
    
    if (!res.ok) {
      throw new Error(`Bundle registration failed: ${res.status}`);
    }
    
    const { attestationId } = await res.json();
    const projectHash = bundle.integrity.projectHash;
    
    // 5. Public verification URL (share this, not the bundle JSON)
    console.log(`https://verify.nexart.io/p/${encodeURIComponent(projectHash)}`);

    Common Failure Cases

    Bundle verifies locally but not on verify.nexart.io

    Cause: The bundle was never registered on the node.verifyProjectBundle()only checks integrity locally; it does not contact the node.

    Fix: Call POST /v1/project-bundle/register with the full bundle JSON and a valid API key.

    Node returns 200 but bundle not found later

    Possible causes:

    • Wrong endpoint (e.g. calling /api/attest with a project bundle instead of /v1/project-bundle/register).
    • Wrong payload shape (sending a single CER instead of the full cer.project.bundle.v1 object).
    • Wrong environment (staging API key against production node, or vice versa).
    • Missing or malformed Authorization header.
    • Bundle was written to a non-persistent code path (e.g. a dry-run flag, a test mode, or a proxy that swallows the body).

    Fix: Confirm the response includesattestationId andsignature, then resolveverify.nexart.io/p/{projectHash} as the authoritative success signal.

    "Partially Verified" confusion

    The verifier reports per-pillar results (Bundle Integrity, Node Signature, Receipt Consistency, Verification Envelope). A partial result usually means one of:

    • The bundle has no node attestation, so node-dependent checks return SKIPPED.
    • Context fields outside the certificateHash scope have been edited; they do not break integrity but are not covered by the hash.
    • Different verifier versions evaluate the same artifact at different protocol versions; minor versions are forward-compatible, breaking changes require a new namespace.

    See Verification Reports for the full per-pillar semantics.

    Builder Checklist

    Before claiming an integration "works", confirm every item:

    • CER verifies locally with verifyCer().
    • Project Bundle verifies locally with verifyProjectBundle().
    • Bundle registered on the node - response includes attestationId and signature.
    • Bundle appears in node proof tables (lookup by projectHash succeeds).
    • verify.nexart.io/p/{projectHash} resolves and returns VERIFIED.

    Trust Model in One Sentence

    SDK proves integrity. Node anchors trust. Verifier provides an independent check. See Trust Model for the full breakdown of who signs what and why each role is necessary.

    See also