Getting Started with NexArt
Start with NexArt in a few steps: install the SDK, certify an execution, read the certificate hash and verify that record locally or via the node API.
Start here: choose your path
Both paths produce Certified Execution Records that anyone can verify. Pick the one that fits how your system works.
- Install the SDK
- Seal a record locally
- Verify it locally
- Optionally attest it
- Check the result
- Sign in and create an API key
- Check readiness
- Create a mapping profile
- Send one event
- Verify, then optionally attest
| SDK | Evidence Bridge | |
|---|---|---|
| Code changes | Yes, a few lines | No, send events you already have |
| Where the hash is created | In your process, by the SDK | By the Bridge, from your mapped event |
| Works offline | Yes (sealing and verification) | No, events are sent to the Bridge |
| Node attestation | Optional, separate call | Optional, separate step |
Not sure? Read Architecture for how records are built, or Integration Surfaces for every option.
Quick Implementation Flow
Four steps. Each has a single responsibility. Following them in order produces a record anyone can verify without trusting your infrastructure.
- Step 1Capture executionWhat: Record provider, model, prompt, input, parameters, and output. All six are required on CertifyDecisionParams.Why: The certificateHash is computed from this data. Capture must happen before sealing.@nexart/signals · createContext() (optional) → passed into certifyDecision(...)
- Step 2Create CERWhat: Seal a CER bundle and compute certificateHash over the strict whitelist (JCS).Why: The hash is the canonical identity of the record. It binds the bundle to its content.certifyDecision(params) · or sealCer(snapshot) for the lower-level path
- Step 3Certify via nodeWhat: Submit the bundle to the attestation node. Receive a signed receipt and verification envelope.Why: The node signs an attestation of the submitted record, separate from the producer integration, and can serve a public verification surface.certifyAndAttestDecision(params, options) · or attest(bundle, options) · POST /v1/cer/ai/certify
- Step 4Verify independentlyWhat: Anyone can re-derive certificateHash, validate the receipt signature, and validate the envelope.Why: Verification requires no trust in your infrastructure or the node beyond its published key.verifyAiCerBundleDetailed(bundle) · or https://verify.nexart.io/c/{bundle.certificateHash}
Minimal working example
One execution, one CER, one certification, one verification. This is the canonical example reused across the docs.
- Creation is local and deterministic (
certifyDecision). It produces a sealed bundle and acertificateHash. No network call. - Certification is node-based (
certifyAndAttestDecisionorattest(bundle, options)). It returns anAttestationReceiptand the bundle gains a verification envelope. - Attestation and public publication are separate. A URL such as
https://verify.nexart.io/c/{certificateHash}resolves only when a public record or public reseal exists; attestation alone does not publish the record. promptandparametersare REQUIRED fields onCertifyDecisionParams, alongsideprovider,model,input, andoutput.
import {
certifyAndAttestDecision,
verifyAiCerBundleDetailed,
} from "@nexart/ai-execution";
// Steps 1-3: capture execution, seal the CER, attest via the node.
// certifyAndAttestDecision is async because it contacts the attestation node.
const { bundle, receipt } = await certifyAndAttestDecision(
{
provider: "openai",
model: "gpt-4o-mini",
prompt: "Should this refund be approved?",
input: { messages: [{ role: "user", content: "Should this refund be approved?" }] },
parameters: { temperature: 0, maxTokens: 1024, topP: null, seed: null },
output: { decision: "approve", reason: "policy_passed" },
},
{
nodeUrl: process.env.NEXART_NODE_ENDPOINT!,
apiKey: process.env.NEXART_API_KEY!,
},
);
const certificateHash = bundle.certificateHash;
const verificationUrl = `https://verify.nexart.io/c/${certificateHash}`;
console.log(certificateHash); // sha256:...
console.log(receipt.attestationId); // node-issued id
console.log(verificationUrl); // https://verify.nexart.io/c/sha256:...
// Step 4: independent verification. No trust in your infrastructure required.
const report = await verifyAiCerBundleDetailed(bundle);
// report.checks.bundleIntegrity -> PASS (Layer 1)
// report.checks.nodeSignature -> PASS (Layer 2)
// report.checks.receiptConsistency -> PASS (Layer 3)
import { certifyDecision, verifyAiCerBundleDetailed } from "@nexart/ai-execution";
// certifyDecision is synchronous and deterministic.
// It produces a sealed CER bundle and certificateHash WITHOUT contacting the node.
// There is no receipt, no envelope, and no public verificationUrl in this flow.
const bundle = certifyDecision({
provider: "openai",
model: "gpt-4o-mini",
prompt: "Should this refund be approved?",
input: { messages: [{ role: "user", content: "Should this refund be approved?" }] },
parameters: { temperature: 0, maxTokens: 1024, topP: null, seed: null },
output: { decision: "approve", reason: "policy_passed" },
});
const certificateHash = bundle.certificateHash;
console.log(certificateHash); // sha256:...
// Local verification: Layer 1 PASS, Layers 2 & 3 SKIPPED.
const report = await verifyAiCerBundleDetailed(bundle);
// To obtain a signed receipt, attest the bundle. Public lookup is a separate publication step.
// via certifyAndAttestDecision(...) or attest(bundle, options).
Using LangChain? See the dedicated LangChain integration page for the optional adapters createLangChainCer / certifyLangChainRun imported from @nexart/ai-execution/langchain.
What NexArt Does
NexArt is the AI Evidence Layer: verifiable execution infrastructure that produces cryptographic evidence about what was executed. NexArt creates Certified Execution Records (CERs), cryptographically bound records of AI or deterministic execution that can be independently verified.
Every CER carries a certificateHash, computed with the canonicalization profile bound to its protocolVersion (for example jcs-v1 for AI Execution V2). That hash is the canonical identity of the record. Optional node attestation produces a signed receipt so anyone can verify the record without trusting your infrastructure.
NexArt is not an observability dashboard, and it does not judge whether a model output was correct, truthful, fair, or compliant with any regulation. It proves canonical artifact integrity, hash equality, signed node attestation, and (for confidential fields) commitment consistency. See the Glossary for precise definitions of these terms.
Multi-step or multi-agent workflow? Follow Path A first, then see Path B: Project Bundle.
Step 1 of 4: Install the SDK
npm install @nexart/ai-executionCurrent version: @nexart/ai-execution@1.4.0. See AI Execution V2 for the full V2 schema reference.
Steps 2 and 3 of 4: Seal and verify locally, then attest (Path A, V2)
The primary happy path. One execution produces one verifiable V2 record. Sealing is fully offline (no API key, no network call); attestation is a single call to the node. Every V2 record declares an executionRole ('advisory' | 'operative' | 'unspecified'), and, when an instruction is present, a matching instructionKind ('system' | 'derived' | 'label'). Both are producer-declared; NexArt never infers them.
import { certifyDecisionV2, attest, verifyCerV2 } from "@nexart/ai-execution";
// certifyDecisionV2 is synchronous. No network call.
const bundle = certifyDecisionV2({
provider: "openai",
model: "gpt-4o-mini",
instruction: "Answer the user's arithmetic question.",
instructionKind: "system",
input: { messages: [{ role: "user", content: "What is 2 + 2?" }] },
parameters: { temperature: 0, maxTokens: 1024, topP: null, seed: null },
output: { text: "4" },
executionRole: "advisory",
});
const certificateHash = bundle.certificateHash;
console.log(certificateHash);
// Local verification, no node call. Re-derives protectedSet and re-checks hashes.
const local = verifyCerV2(bundle);
// local.code === "OK", local.verdict === "VERIFIED"
// Attest to the node. The certificateHash already exists; attest() never
// creates or replaces it.
const attestation = await attest(bundle, {
nodeUrl: process.env.NEXART_NODE_ENDPOINT!,
apiKey: process.env.NEXART_API_KEY!,
});
// attestation.ok === trueThe certificateHash is the canonical identity of the record and does not change between sealing and attestation. attest() POSTs the already-sealed bundle to the node's /api/attest route, which dispatches on bundleType and accepts both cer.ai.execution.v1 and cer.ai.execution.v2.
Note: executionId is not a unique artifact identifier. Always look up records by certificateHash.
cer.ai.execution.v1 is unchanged and remains fully supported. New integrations SHOULD use V2. If you already have a V1 integration, keep using certifyDecision / sealCer from @nexart/ai-execution. For upgrading, see Migration: V1 to V2 and V1/V2 Compatibility.
import { certifyDecision, verifyAiCerBundleDetailed } from "@nexart/ai-execution";
// certifyDecision (V1, from @nexart/ai-execution) is synchronous. No network call.
const bundle = certifyDecision({
provider: "openai",
model: "gpt-4o-mini",
prompt: "What is 2 + 2?",
input: { messages: [{ role: "user", content: "What is 2 + 2?" }] },
parameters: { temperature: 0, maxTokens: 1024, topP: null, seed: null },
output: { text: "4" },
});
const certificateHash = bundle.certificateHash;
const report = await verifyAiCerBundleDetailed(bundle);
// report.checks.bundleIntegrity === "PASS"
// report.checks.nodeSignature === "SKIPPED" (no node attestation yet)
// report.checks.receiptConsistency === "SKIPPED" (no envelope yet)Path B: Workflow with a Project Bundle
For multi-step or multi-agent workflows, certify each step as its own CER and group them into a Project Bundle. The bundle has its own projectHash covering all step certificateHash values.
import { startWorkflow } from "@nexart/agent-kit";
const workflow = startWorkflow({ projectTitle: "Contract review" });
const clauses = await workflow.step("Extract clauses", async () => {
return await llm.call("Extract key clauses...");
});
const risks = await workflow.step("Summarize risks", async () => {
return await llm.call("Summarize risks from: " + clauses);
});
const bundle = workflow.finish();
// bundle.integrity.projectHash is the verifiable hashFor public verification on verify.nexart.io, the bundle must be registered on the node. See End-to-End Verification for the full registration flow.
Step 4 of 4: Verify the record
Verification can be performed independently. Open https://verify.nexart.io and paste the certificateHash, or open the URL directly:
https://verify.nexart.io/c/{certificateHash}Official Example Repos
Common mistakes
- Wrong: Setting version: "1.0" on the bundleRight: Use version: "0.1" (matches cer.ai.execution.v1).Why: An incorrect version changes the canonical projection and breaks certificateHash recomputation.
- Wrong: Hashing the full bundle (including meta.attestation, signature, receipt)Right: Hash only the strict whitelist: bundleType, version, createdAt, snapshot, context, contextSummary (JCS).Why: meta and attestation are added after sealing. Hashing them produces a different, non-verifiable hash.
- Wrong: Trying to verify the Verification Envelope from a publicly redacted recordRight: Layer 3 envelope verification requires the full attestation projection. Redacted public payloads support Layer 1 and Layer 2 only.Why: Envelope signature covers a 5-field projection that may be removed by redaction.
- Wrong: Mutating the bundle after certification (re-ordering keys, adding fields, normalizing dates)Right: Treat the certified bundle as immutable. Persist it byte-for-byte.Why: Any mutation invalidates certificateHash and the receipt. The node enforces EXECUTION_MUTATION_DETECTED (409) on resubmit.
- Wrong: Looking up records by executionIdRight: Always look up by certificateHash. executionId is not a unique artifact identity.Why: Two attempts of the same execution can share an executionId but produce different certificateHashes.
What happens if it fails
| Layer | Failure | Meaning | Action |
|---|---|---|---|
| Layer 1: Integrity | certificateHash mismatch | The 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 Receipt | Receipt signature invalid | The 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 Envelope | Envelope signature invalid or projection mismatch | The 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. |
| Node | EXECUTION_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. |
Next Steps
- Quickstart: the shortest path through both paths
- AI Execution V2: full V2 schema, executionRole, instructionKind, decisionRefs
- Migration: V1 to V2 and V1/V2 Compatibility
- Glossary and AIEF: precise terminology and claim boundaries
- Project Bundles: how multi-step workflows are grouped and verified
- End-to-End Verification: node registration and public verification
- LangChain and n8n: framework integrations
- CLI: create and verify CERs from the command line