Skip to content

API Reference

Frank Yglesias Bertheau edited this page Jul 7, 2026 · 1 revision
<h1>ᚾ&nbsp;NornGate — API Reference</h1>

Scope note. This documents the API contract that follows from the runtime behavior described across these docs. Treat the running service's OpenAPI spec as authoritative and reconcile exact paths, field names, and shapes against it.

There are two surfaces:

  1. The gated request path — an agent makes its normal request to a target resource; the mesh enforces G0–G4 transparently and returns either the upstream response or a fail-closed status. There is no special "submit action" endpoint — enforcement is inline.
  2. The control API — NornGate's own endpoints (audit, receipts, approvals, keys), served from Asgard.

Base URLs. Gated requests go to the target realm host (https://app.norngate.com/… for Midgard). Control API lives at https://asgard.norngate.com/v1. Versioning is path-based (/v1); breaking changes ship under /v2.


ᛗ Authentication

  • In-mesh callers — mutual TLS with a SPIFFE SVID; identity is automatic, no token handling. This is how agents authenticate.
  • External callers — an OIDC bearer token (Authorization: Bearer <token>, RFC 6750) or an API key, admitted through Vanaheim.

Every request is authenticated at G0; an unauthenticated or invalid caller is denied 401 before any other gate runs.


ᚦ The gated request contract

An agent's outbound request is intercepted at the Envoy sidecar and run through the gates. The agent does not change its code — it adds headers and reads the verdict.

Request headers

Header Required Purpose
Authorization external only Bearer token / API key
Idempotency-Key state-changing Exactly-once commit at G4
Content-Type body requests application/json

References. RFC 9457 (Problem Details for HTTP APIs); RFC 6750 (OAuth 2.0 Bearer); SPIFFE/SPIRE (mTLS identity); RFC 8032 (Ed25519, receipt signatures); RFC 3339 (timestamps). Naming doctrine: Prose Edda / Poetic Edda, per Norse Cosmology & Platform Design.

ᚾ NornGate — API Reference

Scope note. This documents the API contract that follows from the runtime behavior described across these docs. Treat the running service's OpenAPI spec as authoritative and reconcile exact paths, field names, and shapes against it.

There are two surfaces:

  1. The gated request path — an agent makes its normal request to a target resource; the mesh enforces G0–G4 transparently and returns either the upstream response or a fail-closed status. There is no special "submit action" endpoint — enforcement is inline.
  2. The control API — NornGate's own endpoints (audit, receipts, approvals, keys), served from Asgard.

Base URLs. Gated requests go to the target realm host (https://app.norngate.com/… for Midgard). Control API lives at https://asgard.norngate.com/v1. Versioning is path-based (/v1); breaking changes ship under /v2.


ᛗ Authentication

  • In-mesh callers — mutual TLS with a SPIFFE SVID; identity is automatic, no token handling. This is how agents authenticate.
  • External callers — an OIDC bearer token (Authorization: Bearer <token>, RFC 6750) or an API key, admitted through Vanaheim.

Every request is authenticated at G0; an unauthenticated or invalid caller is denied 401 before any other gate runs.


ᚦ The gated request contract

An agent's outbound request is intercepted at the Envoy sidecar and run through the gates. The agent does not change its code — it adds headers and reads the verdict.

Request headers

Header Required Purpose
Authorization external only Bearer token / API key
Idempotency-Key state-changing Exactly-once commit at G4
Content-Type body requests application/json
curl -X POST https://app.norngate.com/records/4471 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: idem_abc123" \
  -H "Content-Type: application/json" \
  -d '{"field": "value"}'

On allow / commit — the upstream response, plus verdict headers:

HTTP/1.1 200 OK
X-NornGate-Request-Id: req_abc123
X-NornGate-Verdict: allow
X-NornGate-Outcome-Id: out_9a2
Link: </v1/receipts/out_9a2>; rel="receipt"

On deny — a fail-closed status with an RFC 9457 problem body:

HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
X-NornGate-Request-Id: req_abc123
{
  "type": "urn:norngate:error:policy-denied",
  "title": "Policy denied",
  "status": 403,
  "detail": "agent role cannot access resource type 'model'",
  "gate": "policy",
  "requestId": "req_abc123"
}

The X-NornGate-Request-Id is the key into [Urd](Urd-Ledger) — the same value the audit record and receipt carry.


ᚲ Control API

Served from Asgard; every call is authenticated, authorized, and itself audited.

Method Path Purpose
GET /v1/audit Query decision/outcome records
GET /v1/audit/{id} Fetch one record
GET /v1/receipts/{outcomeId} Fetch a signed outcome receipt
GET /v1/keys Ledger public keys (verify signatures)
GET /v1/approvals List approvals (filter by state)
POST /v1/approvals/{approvalId} Decide a pending approval
GET /v1/healthz Liveness / readiness

Query the ledger.

GET /v1/audit?gate=policy&decision=deny&from=2026-07-06T00:00:00Z&to=2026-07-06T23:59:59Z&limit=50

Returns an array of records (PII payloads by reference; resolved only for authorized readers). Record shape: [Urd Ledger](Urd-Ledger).

Fetch a verifiable receipt. Verify sig against the key at GET /v1/keys identified by keyId.

{
  "outcomeId": "out_9a2",
  "requestId": "req_abc123",
  "resource": "user-record:4471",
  "billable": true,
  "prev_hash": "sha256:7c4d",
  "sig": "ed25519:a12e",
  "keyId": "urd-2026-07",
  "timestamp": "2026-07-06T10:32:02Z"
}

Decide an approval (the human side of G2).

curl -X POST https://asgard.norngate.com/v1/approvals/apr_5c1 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"decision": "approve"}'

decision is approve or deny; the outcome is recorded to Urd and debits the tenant's approval budget.


ᚺ Error model

Denials use RFC 9457 Problem Details (application/problem+json) with a stable type URN, the deciding gate, and the requestId. Both failure modes are fail-closed:

Status type (urn:norngate:error:…) Gate Mode
400 malformed-request G0 denial
401 unauthenticated G0 denial
403 policy-denied / approval-denied G1 / G2 denial
408 approval-timeout G2 timeout
409 write-conflict G4 denial + timeout
429 rate-limited G0 denial
500 sandbox-failure G3 denial + timeout
503 gate-unavailable G0 / G1 timeout

Full causes and remedies: [Error Codes](Error-Codes).


ᚷ Conventions

  • IdempotencyIdempotency-Key is required on state-changing requests. A repeated key returns the already-committed outcome (exactly-once at G4); scope one key per logical action (a UUID is fine). See [Deterministic Execution](Deterministic-Execution).
  • Pagination — cursor-based: ?cursor=<opaque>&limit=<n>; responses carry nextCursor (null at the end). Do not construct cursors by hand.
  • Rate limits — per identity/tenant token bucket at G0; on exhaustion, 429 with a Retry-After header.
  • Time — all timestamps are RFC 3339 UTC.
  • Idempotency + retries — safe to retry any request carrying an Idempotency-Key; the side effect commits once regardless of delivery count.

ᚱ Next steps

  • [Urd Ledger](Urd-Ledger) — record and receipt formats, signature verification.
  • [Error Codes](Error-Codes) — the full status/type catalogue.
  • [Configuration](Configuration) — gate, policy, and realm YAML.
  • [Gates & Attributes](Gates-and-Attributes) — what a policy decision evaluates.

Iconography

Section glyphs are Elder Futhark runes (Unicode Runic block, U+16A0–U+16FF) — semantic, not emoji. Full set on [Home](Home#iconography):

Rune Name Gloss Marks
Nauðiz need, constraint the platform mark
Mannaz the self, identity authentication
Thurisaz thorn, gateway the gated request contract
Kenaz the torch, access control API
Hagalaz hail, failure states error model
Gebo balanced exchange conventions
Raidō the ride, the road next steps

References. [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) (Problem Details for HTTP APIs); [RFC 6750](https://www.rfc-editor.org/rfc/rfc6750) (OAuth 2.0 Bearer); [SPIFFE](https://spiffe.io/)/SPIRE (mTLS identity); [RFC 8032](https://www.rfc-editor.org/rfc/rfc8032) (Ed25519, receipt signatures); RFC 3339 (timestamps). Naming doctrine: Prose Edda / Poetic Edda, per [Norse Cosmology & Platform Design](Norse-Cosmology-and-Platform-Design).

Clone this wiki locally