Project Bundle Registration
Registration turns a locally verified bundle into a publicly verifiable artifact on verify.nexart.io.
Local verification is not public verification
A Project Bundle that passes
verifyProjectBundle() locally is not publicly verifiable until it is registered on the node. 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..."
}
}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