Documentation

How NordAI is put together

A Next.js website, a Go API with PostgreSQL and Redis, a private 9Router instance and a Node.js CLI. These docs describe the shipped system and its limits.

Quick start

Create an account, verify your email, then issue a key in Dashboard → API keys.

npm install -g nordai && nordai login

Your first request can be made from the CLI (nordai "summarise this repository") or directly against the gateway with an API key. Use GET /api/v1/me/models to discover which model ids your plan allows — never guess an id.

Architecture

Traffic enters through Nginx over HTTPS. The Next.js app serves the website and dashboards and calls the Go API over the internal Docker network. The API is the only service that talks to PostgreSQL, Redis and the AI router.

Internet
  → Nginx (TLS, HSTS, rate limits)
  → Next.js website + dashboard
  → Go API (auth, entitlements, gateway, billing)
  → PostgreSQL + Redis (private)
  → 9Router (private network, never exposed)
  → Authorized upstream AI provider
  • The router dashboard is bound to the internal network only.
  • PostgreSQL and Redis have no published host ports in production.
  • The NORD_AI_ROUTER_API_KEY exists only in the API container environment.

Authentication

Browser sessions use an opaque HttpOnly cookie plus a CSRF cookie and a matching X-CSRF-Token header for mutating requests. CLI access uses a revocable device credential or a customer API key sent as Authorization: Bearer ….

  • Passwords are hashed with bcrypt (cost 12).
  • API keys are 256-bit random values; only their SHA-256 hash is stored.
  • Password reset and email verification tokens are single-use and expire.
  • Optional TOTP two-factor authentication is available in account settings.
  • Login attempts are throttled per account and per IP.

Gateway behaviour

POST /api/v1/chat/completions is OpenAI-compatible and accepts stream: true. The gateway enforces, in order: account status → email verification → maintenance/feature flags → plan entitlement → model allowlist → rate limit → concurrency → atomic usage reservation → forwarding.

  • The requested model is rewritten to an approved model id; unknown ids are rejected.
  • Output tokens are capped by the plan and a server-side cap.
  • Idempotency-Key makes retries safe: a duplicate returns 409 duplicate_request and is not billed.
  • Token counts come from the upstream response. Missing counts remain empty in the database.
  • Fallback only occurs on retryable upstream failures, and only to other models your plan allows.

Quotas and errors

Usage is reserved inside a transaction holding a per-user advisory lock, so concurrent requests cannot exceed a plan limit. A failed upstream request is recorded as failed and its reserved request is returned.

Structured errors use a single shape:

{
  "error": {
    "code": "daily_limit_reached",
    "message": "Daily allowance reached (25 of 25 requests on NordAI Free)…",
    "request_id": "…",
    "details": { "reset_at": "2026-10-30T17:00:00Z", "upgrade_url": "…" }
  }
}

Common codes: authentication_required, email_not_verified, model_not_in_plan, rate_limited, concurrency_limit, daily_limit_reached, monthly_limit_reached, duplicate_request, upstream_rate_limited, upstream_quota_exhausted, upstream_unavailable.

Security model

  • All authorization is server-side; hidden links are not access control.
  • Workspace tools resolve every path and reject traversal and symlink escapes.
  • Administrative changes are written to an audit log with actor, target and metadata.
  • Prompts and file contents are not logged by default.
  • Webhook signatures are verified with a timestamp tolerance and constant-time comparison.
  • Provider terms are verified before a model can serve paid traffic.

Known limitations

  • PayinAja cannot be enabled: no current official API specification could be verified. Only the development mock provider is available until a provider is implemented against its documentation.
  • Email delivery requires SMTP configuration. Without it, verification and reset links are written to the API log (development only).
  • Redis is optional for a single API instance; without it, rate limits are per-instance rather than cluster-wide.
  • The CLI supports manual API-key login and device authorization. OS keychain integration depends on the platform; otherwise credentials are stored in a 0600 file.
  • The model catalogue is only as complete as the connected router instance.