-
Notifications
You must be signed in to change notification settings - Fork 0
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:
- 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.
- 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.
- 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.
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.
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:
- 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.
- 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.
- 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.
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.
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=50Returns 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.
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).
-
Idempotency —
Idempotency-Keyis 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 carrynextCursor(null at the end). Do not construct cursors by hand. -
Rate limits — per identity/tenant token bucket at G0; on exhaustion,
429with aRetry-Afterheader. - 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.
- [Urd Ledger](Urd-Ledger) — record and receipt formats, signature verification.
- [Error Codes](Error-Codes) — the full status/
typecatalogue. - [Configuration](Configuration) — gate, policy, and realm YAML.
- [Gates & Attributes](Gates-and-Attributes) — what a policy decision evaluates.
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).
Welcome
Getting Started
Core Concepts
Guides
- Guides
- Configuring Gates
- Setting Up Subdomains (Realms)
- Integrating AI Agents
- Monitoring & Observability
- Disaster Recovery (Ragnarök Drill)
- Custom Domains & TLS
Reference
Silence means no.