# Attestation Node

URL: https://docs.nexart.io/docs/attestation-node

The NexArt attestation node contract: what the node signs, the metadata it records, its error codes, and the boundary between node attestation and independent.

## Node Role in the Protocol

Attestation nodes act as independent witnesses for Certified Execution Records. A node verifies the integrity of a CER bundle and signs an attestation receipt confirming that the record existed at a specific point in time.

Nodes do not own or control the execution data. Their role is limited to validating bundle integrity and producing a signed receipt.

## Where trust comes from

Trust in NexArt is derived from three independent properties:

- Deterministic integrity.- The `certificateHash` binds the record to its exact contents.
- Any modification produces a different hash.
- Node attestation.- A node signs the `certificateHash` and records when it was observed.
- This provides a verifiable witness, not authority over the data.
- Independent verification.- Verification is performed using open algorithms and published keys.
- The node does not control verification outcomes.

The node acts as a cryptographic witness, not a source of truth. Verification remains valid even if the node is unavailable, provided its public keys are known.

## Minimal Node Requirements

A NexArt attestation node must satisfy the following protocol contract:

- Verify the CER bundle structure.
- Recompute the `certificateHash` from the canonical bundle.
- Confirm the computed `certificateHash` matches the declared value.
- Generate an attestation timestamp.
- Produce a signed attestation receipt binding the `certificateHash`, timestamp, node identity, and signing key identifier.
- Publish signing keys through the node metadata endpoint.

## What Does the Node Do?

The attestation node is an independent witness in the NexArt system. It does not define truth or control verification. When the API submits a CER bundle, the node:

- Validates the bundle structure
- Records a precise timestamp
- Signs the CER using Ed25519
- Returns a signed receipt (stored at `meta.attestation` in the CER bundle)

## Attestation Modes

The node supports two attestation modes:

- Full signed receipt. The node attests the complete CER including snapshot contents. The default for `cer.ai.execution.v1` bundles.
- Hash-only timestamp. The node signs only the `certificateHash`. Used for legacy or incomplete records. Produces a `hash-only-timestamp` bundle.

## Node Metadata Endpoint

All NexArt attestation nodes must publish a node metadata document at:

`/.well-known/nexart-node.json`

This document exposes the node identity and signing keys required for independent receipt verification.

The canonical node publishes at node.nexart.io.

Required fields:

- nodeId: unique identifier for the attestation node.
- activeKid: the key identifier currently used for signing.
- keys[]: array of signing key entries. Each entry requires:- kid: unique key identifier.
- algorithm: signing algorithm (Ed25519).
- publicKey: the public key material.
- status: key status (e.g. `active`, `retired`).

Node Metadata Document

```
GET node.nexart.io/.well-known/nexart-node.json

{
  "nodeId": "nexart-node-primary",
  "activeKid": "key_01HXYZ...",
  "keys": [
    {
      "kid": "key_01HXYZ...",
      "algorithm": "Ed25519",
      "publicKey": "MCowBQYDK2VwAyEA...",
      "status": "active"
    }
  ]
}
```

## Signing Details

- Algorithm. Ed25519.
- Key rotation. The node may rotate keys over time. Each receipt includes a `kid` that identifies which key was used. The `activeKid` field indicates the current primary signing key.
- Key discovery. All active and historical keys are published at the well-known endpoint so past receipts remain verifiable.

## Verifying Against the Node

To independently verify a signed receipt:

- Fetch the node&#x27;s keys from `/.well-known/nexart-node.json`
- Find the key matching the receipt&#x27;s `kid`
- Verify the Ed25519 signature over the canonical receipt payload

Or use the public verifier at verify.nexart.io.

Verification can be performed at two levels:

- Full verification requires access to the complete CER bundle.
- Public verification relies on redacted representations and confirms attestation without exposing underlying execution data.

## Node Compatibility

A CER remains valid regardless of which compliant NexArt attestation node produced the receipt.

Verification tools must rely only on:

- The CER bundle
- The signed receipt
- The node&#x27;s published public key material

Verification must not depend on the continued availability of the original attestation node beyond its published verification material.

## Persistence and Registration

Beyond signing, the canonical node persists registered artifacts. Persistence is what makes an artifact resolvable on verify.nexart.io.

- `POST /api/attest` persists a single CER attestation.
- `POST /v1/project-bundle/register` persists a full Project Bundle.

Common registration failure modes:

- AUTH_INVALID: missing or wrong API key.
- PERSISTENCE_FAILED: the bundle was signed but writing to the proof tables failed; the artifact will not resolve publicly. Retry with the same payload.
- HASH_MISMATCH: the recomputed hash does not match the declared hash; usually caused by undefined values breaking canonical JSON.

A 200 response is not sufficient evidence of success. Always confirm against the public verifier as the authoritative success signal. See End-to-End Verification.

Note: NexArt nodes also accept `POST /api/stamp` as a backward-compatible alias for `/api/attest`. New integrations should use `/api/attest`. The alias will remain available for at least 12 months from this documentation change.

## Redacted Reseal Behavior

The node MAY return a redacted reseal of the original CER for public verification. Reseal exists so that artifacts containing sensitive metadata can still be publicly verified after redaction, without exposing the private fields.

A reseal is a NEW bundle with the following properties:

- bundleType: `signed-redacted-reseal`
- NEW certificateHash: covers the resealed (redacted) content. This is what the public verifier validates.
- Provenance pointer: references the ORIGINAL `certificateHash`. Reference only; not validated.
- Fresh node signature: covers the resealed content under `meta.attestation`.

The original and resealed hashes can legitimately coexist. They describe the same execution at different visibility levels. See Verification Semantics for the rules to apply when handling reseals.

## Certification Flow (protocolVersion 1.3.1)

Protocol `1.3.1`enables first-class confidential execution. The client submits raw fields to `POST /v1/cer/ai/certify` and the node performs sealing. See Confidential Execution for the full model.

- Client sends: `prompt`, raw `input`, raw `output`, and full `parameters`.
- Node seals: `input` and `output` into commitment envelopes via `sealConfidential` (HMAC-SHA256) using deterministically derived per-field salts.
- Node builds the CER with envelopes in place of plaintext, computes `certificateHash`, and returns the attested bundle.
- Raw `input` and `output` are transmitted over TLS and processed transiently by the node. They are excluded from the certified snapshot and from `proof_json`, and the documented confidential flow is designed not to persist them.

Canonical request body:

POST /v1/cer/ai/certify - protocolVersion 1.3.1

```
{
  "executionId": "exec_123",
  "provider": "openai",
  "model": "gpt-4o",
  "prompt": "You are a financial analyst.",
  "input": "Summarize the risks.",
  "output": "Revenue decline...",
  "parameters": {
    "temperature": 0,
    "maxTokens": 1024,
    "topP": 1,
    "seed": null
  },
  "protocolVersion": "1.3.1",
  "appId": "example-app"
}
```

Clients MUST NOT pre-hash or pre-redact `input`/`output` for 1.3.1. The hash-bound omission pattern from 1.2.0 is no longer the confidentiality model.

## Node API Endpoints

The canonical attestation node exposes the following endpoints. Authenticated endpoints require `Authorization: Bearer NEXART_API_KEY`.

| Endpoint | Auth | Purpose | Typical use |
| --- | --- | --- | --- |
| POST /v1/cer/ai/create | API key | Create a CER bundle without attestation. | Deferred attestation flows. |
| POST /v1/cer/ai/certify | API key | Create and attest a CER in one call. | Default integration path. |
| POST /v1/cer/verify | Public | Verify a single CER against the node's view. | Server-side verification of a held bundle. |
| GET /v1/cer/public?certificate_hash=<hash> | Public | Fetch the public-safe (redacted) representation of a CER. | Backing the public verifier UI. |
| POST /v1/project-bundle/register | API key | Register a Project Bundle and obtain a project-level receipt. | Multi-step or multi-agent workflows. |
| POST /v1/project-bundle/verify | Public | Verify a Project Bundle. | Server-side verification of a held Project Bundle. |
| POST /v1/admin/recertify-batch | Admin key | Re-seal affected executions (e.g. v0.16.0 → v0.16.1 envelope alignment). | Operator remediation only. |

## Idempotency and Mutation Rules

- One `execution_id` maps to one `certificateHash` forever.
- Re-submitting the same `execution_id` with the same content is idempotent and returns the original record.
- Re-submitting the same `execution_id` with mutated content returns `409 EXECUTION_MUTATION_DETECTED`. The original record is preserved.
- To represent a corrected execution, create a new record with a new `execution_id`.

## Error Codes

| Code | Meaning |
| --- | --- |
| CERTIFICATE_HASH_MISMATCH | Recomputed certificateHash does not match the value declared in the bundle. |
| BUNDLE_HASH_MISMATCH | Bundle hash does not match the receipt or envelope reference. |
| NODE_SIGNATURE_INVALID | Ed25519 signature on the receipt fails verification against the published key. |
| RECEIPT_BUNDLE_HASH_MISMATCH | Receipt references a different certificateHash than the bundle. |
| EXECUTION_MUTATION_DETECTED | Same execution_id submitted with mutated content. Returned with HTTP 409. |
| VALIDATION_ERROR | Missing or malformed field. Response carries details[]. HTTP 400. |
| LOOP_MODE_ERROR | Code Mode: totalFrames outside 2..MAX_TOTAL_FRAMES (default 1800) or loop with no draw(). HTTP 400. |
| PROTOCOL_SCHEMA_UNSATISFIED | Content fails the requested protocol's SDK check. HTTP 422. |
| UNAUTHORIZED | Missing, malformed, or rejected API key. |
| SERVICE_UNAVAILABLE | Database temporarily unavailable. Node fails closed and never waves the request through. HTTP 503. |
| QUOTA_EXCEEDED | Account or project quota exceeded. |

## Self-Hosted Nodes

Roadmap. Self-hosted attestation nodes are not currently available. This feature is planned for a future release.
