From Execution to Public Verification
The complete lifecycle from local integrity to node attestation to public verification. Three trust states, not interchangeable.
A bundle that verifies locally is not publicly verifiable
verifyProjectBundle() locally but has NOT been registered on the attestation node will NOT resolve onverify.nexart.io/p/{projectHash}. Registration is a separate, REQUIRED step.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.
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}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 CERPOST /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 CERhttps://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.
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 bundleverificationEnvelope- canonical envelope covering the project-level receiptsignature- Ed25519 signature over the envelope by the node's signing keymetadata- node identity, key id, timestamp, protocol version
Success Definition
Registration is successful ONLY when ALL of the following are true:
- The node returns a 2xx response with the fields above.
- The bundle is written to the node's proof tables.
https://verify.nexart.io/p/{projectHash}resolves and returnsVERIFIED.
A 200 response alone is not sufficient evidence of success. Always confirm against the public verifier.
Minimal Correct Flow
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/attestwith a project bundle instead of/v1/project-bundle/register). - Wrong payload shape (sending a single CER instead of the full
cer.project.bundle.v1object). - Wrong environment (staging API key against production node, or vice versa).
- Missing or malformed
Authorizationheader. - 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
attestationIdandsignature. - Bundle appears in node proof tables (lookup by
projectHashsucceeds). verify.nexart.io/p/{projectHash}resolves and returnsVERIFIED.
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
- Project Bundle Registration - the registration step in detail.
- Verification Statuses & Errors - what every result and error means.
- Multi-step & Multi-agent Workflows - applying this to agents.
- Public Reseals & Redacted Verification - why public hashes can differ.