Project Bundle Registration
Register a Project Bundle with the NexArt attestation node: request shape, step ordering, parent references, project hash and the returned verify URL.
Local verification is not public verification
A Project Bundle that passes
verifyProjectBundle() locally is not attested until it is registered on the node, and registration alone does not guarantee public lookup. It will NOT resolve on verify.nexart.io.When to use registration
Use when
- Multiple steps or agents
- Workflow-level public verification
- External auditor must resolve without your SDK
- Node-signed receipt required as trust anchor
Skip when
- Single execution (use Path A +
/api/attest) - Independent decisions, not a workflow
- Internal-only audit trail, never resolved publicly
The three verification layers
These are distinct and not interchangeable. A bundle can pass one and still need the next.
- Local SDK verification.
verifyProjectBundle(bundle)recomputes hashes and checks step integrity against the bundle's own contents. It proves the artifact has not been modified since it was produced. - Node registration.
POST /v1/project-bundle/registerpersists the bundle in the node's proof tables and returns a signed receipt. This is the trust anchor for any third party. - Public verification.
verify.nexart.io/p/{projectHash}resolves the registered bundle and re-runs verification against the node's stored copy. Anyone with the projectHash can verify, without your code or your SDK.
Minimal end-to-end flow
import {
certifyDecision,
createProjectBundle,
verifyProjectBundle,
registerProjectBundle,
} from "@nexart/ai-execution";
// 1. Produce step CERs (each step is its own verifiable record).
const stepA = await certifyDecision({ /* step A inputs */ });
const stepB = await certifyDecision({ /* step B inputs */ });
// 2. Group steps into a Project Bundle (computes projectHash).
const bundle = await createProjectBundle({
projectId: "workflow-123",
steps: [stepA.cer, stepB.cer],
});
// 3. Local verification - integrity only.
const local = await verifyProjectBundle(bundle);
if (!local.ok) throw new Error("Bundle is not internally consistent");
// 4. Register on the node - REQUIRED for public verification.
const reg = await registerProjectBundle(bundle, {
apiKey: process.env.NEXART_API_KEY!,
});
console.log("Public URL:", `https://verify.nexart.io/p/${reg.projectHash}`);Successful registration response
{
"ok": true,
"projectHash": "sha256:7d4a...e91",
"registeredAt": "2026-04-21T12:00:00Z",
"receipt": {
"alg": "Ed25519",
"kid": "node-key-2026-01",
"sig": "base64..."
}
}Container unchanged; steps may be V1, V2, or mixed
What the registration helper does
- POSTs the canonical bundle JSON to
/v1/project-bundle/register. - Authenticates with your
NEXART_API_KEY. - Receives a node-signed receipt over the bundle's
projectHash. - Is idempotent: re-registering the same bundle returns the existing record.
Failure modes
For a complete catalogue of node responses and what to do about them, see Verification Statuses & Errors. The most common ones at registration time:
HASH_MISMATCH- the recomputed projectHash does not match the value in the submitted bundle. Usually caused by non-canonical JSON (extra whitespace, undefined values, key reordering).PERSISTENCE_FAILED- node accepted the request but could not write to its proof tables. Retry with backoff; the operation is idempotent onprojectHash.AUTH_INVALID- missing or rejected API key.
Builder checklist before claiming "it works"
- Each step CER verifies locally
- Project Bundle verifies locally
- Bundle registered on the node (success response received)
verify.nexart.io/p/{projectHash}resolves