Skip to content

Latest commit

 

History

History
364 lines (287 loc) · 16.2 KB

File metadata and controls

364 lines (287 loc) · 16.2 KB
Error in user YAML: (<unknown>): mapping values are not allowed in this context at line 2 column 41
---
title: Http Api
description: Every NullRun HTTP endpoint: /api/v1/gate, /api/v1/track, /api/v1/capabilities, /api/v1/heartbeat, and the control-plane WebSocket protocol.
---

HTTP API

This page lists the endpoints a user — or their SDK — actually calls. Internal admin endpoints (pricing backfill, gateway operator APIs) are not exposed here; see the gateway repo for the full internal surface.

Base URL:

  • Production: https://api.nullrun.io/api/v1
  • WebSocket control plane: wss://api.nullrun.io/ws/control/{org_id}

The {org_id} for the WebSocket comes from the credential bundle returned by POST /api/v1/auth/verify (organization_id field). The SDK negotiates this automatically — only set the URL by hand when you are building a custom WebSocket client.

The OpenAPI spec is generated from the router and is the source of truth.

Authentication

Two schemes — they are not interchangeable.

X-API-Key + HMAC (SDK → gateway)

All SDK-traffic endpoints (/track, /track/batch, /gate, /execute, /check) require:

Header Value
X-API-Key API key (nr_live_...)
X-Signature hex(HMAC-SHA256(secret_key, timestamp:api_key:body_sha256))
X-Signature-Timestamp Unix epoch seconds (rejected if older than NULLRUN_HMAC_MAX_AGE_SECS, default 300)
X-Workflow-Id (optional) binds the call to a workflow context

The SDK computes and signs every request automatically once NULLRUN_API_KEY and NULLRUN_SECRET_KEY are set. The gateway default for NULLRUN_HMAC_REQUIRED is false for backward compatibility — operators must set it explicitly to true in production. When NULLRUN_HMAC_REQUIRED=true, unsigned SDK requests are rejected with 401 and the SDK-auth middleware emits a per-request WARN so the gap is visible in logs.

SDK requests to /api/v1/orgs/{org_id}/* are also checked for org-mismatch: the org claimed in the URL must match the org the API key was minted for. Mismatch → 403.

Authorization: Bearer <session_token> (dashboard / admin)

Dashboard endpoints (/orgs/..., /admin/...) use session tokens obtained from POST /api/v1/auth/login or the OAuth flow (/auth/oauth/register). Pass as Authorization: Bearer <token>.

SDK endpoints

These are the endpoints the SDK calls. You will not normally hit them by hand, but the contracts are stable and the OpenAPI spec documents every field.

Method Path Called by
POST /api/v1/auth/verify init() — verifies the API key and returns the full credential bundle (HMAC secret_key, org context, plan, workflow_id, key_version, etc.)
GET /api/v1/capabilities init() — protocol negotiation
POST /api/v1/gate Pre-flight + policy evaluation + budget reservation (called from @protect entry)
POST /api/v1/track Single-event commit (reservation_id + idempotency_key)
POST /api/v1/track/batch Batched events (≤ 100 per batch) — opt-in fallback when single-event is disabled
GET /api/v1/orgs/{org_id}/policies Policy fetch (called from SDK on first @protect and on policy_invalidated WS push)
GET /api/v1/orgs/{org_id}/workflows/{workflow_id} Workflow lookup (called from SDK on first gate per workflow)
GET /api/v1/orgs/{org_id}/status Control-plane poll fallback (only used when WS is down)
POST /api/v1/heartbeat Time-based cadence heartbeat
POST /api/v1/cancel Cancel an in-flight execution. Idempotent; the reservation TTL cleans up even if the call doesn't reach the gateway.
Method Path Status
POST /api/v1/check Deprecated — returns 410 Gone with replacement: /api/v1/gate. Use /gate for new integrations.
POST /api/v1/execute Live — per-tool invocation with gate pre-flight and budget reservation (thin adapter in front of the unified gate engine).

Auth

Method Path Purpose
POST /api/v1/auth/register Create account, returns API key + secret
POST /api/v1/auth/login Dashboard session token
POST /api/v1/auth/verify Verify API key + return full credential bundle
POST /api/v1/auth/oauth/register OAuth signup (returns API key + secret)

POST /api/v1/auth/verify response fields

Field Type Notes
organization_id string (UUID) Canonical org identifier
organization_name string | null Canonical org display name
plan string Plan tier (lite, starter, growth, scale, enterprise_unlimited, …)
features object Plan-feature flags resolved for this org
limits object Plan-limits block (workflows, seats, …)
role string | null Member role; null on API-key path — SDK treats null as "role unknown, escalate to session auth"
workflow_id string | null Workflow this API key is bound to; null on unbound / legacy keys
secret_key string | null HMAC secret the SDK uses to sign requests — distinct from the API key itself
key_version number | null Current active HMAC key version; SDK compares against its cached value to detect rotation

Workflows

Method Path Purpose
POST /api/v1/orgs/{org_id}/workflows Create workflow
GET /api/v1/orgs/{org_id}/workflows List workflows
GET /api/v1/orgs/{org_id}/workflows/{workflow_id} Get workflow
PATCH /api/v1/orgs/{org_id}/workflows/{workflow_id} Update (budget, name, …)
POST /api/v1/orgs/{org_id}/workflows/{workflow_id}/pause Pause (broadcasts state_change over WS)
POST /api/v1/orgs/{org_id}/workflows/{workflow_id}/resume Resume
POST /api/v1/orgs/{org_id}/workflows/{workflow_id}/kill Kill (broadcasts state_change over WS)

Policies

Method Path Purpose
POST /api/v1/orgs/{org_id}/policies Create
GET /api/v1/orgs/{org_id}/policies List (a single policy is not addressable by id — read it from the list response)
PATCH /api/v1/orgs/{org_id}/policies/{policy_id} Update
DELETE /api/v1/orgs/{org_id}/policies/{policy_id} Delete
POST /api/v1/orgs/{org_id}/policies/{policy_id}/toggle Toggle a policy active/inactive (dashboard PATCH 404 fix)
GET /api/v1/orgs/{org_id}/policies/templates List policy templates
POST /api/v1/orgs/{org_id}/policies/templates/{template_id}/enable Enable a template
DELETE /api/v1/orgs/{org_id}/policies/templates/{template_id} Disable a template

Most-restrictive-wins composition across applicable policies — see Concepts → Policies.

Approvals

Programmatic approval / denial — useful for on-call bots and CI runbooks. Dashboard uses the same endpoints internally. See Concepts → Human approval for the end-to-end flow.

Method Path Purpose
POST /api/v1/orgs/{org_id}/approvals/{approval_id}/approve Approve a pending approval. Idempotent — already-approved returns 409 approval_already_decided.
POST /api/v1/orgs/{org_id}/approvals/{approval_id}/deny Deny a pending approval. The SDK raises WorkflowKilledInterrupt for the parked agent.

Executions, audit, observability

Method Path Purpose
GET /api/v1/orgs/{org_id}/executions List executions
GET /api/v1/orgs/{org_id}/executions/{execution_id} One execution
GET /api/v1/orgs/{org_id}/audit-log Audit trail
GET /api/v1/orgs/{org_id}/audit-log/export Start an async audit-log export job (returns a job id)
POST /api/v1/orgs/{org_id}/audit-log/export Same — POST variant, useful from web forms
GET /api/v1/orgs/{org_id}/audit-log/export/{job_id}/status Poll export job status (pending / ready / failed)
GET /api/v1/orgs/{org_id}/audit-log/export/{job_id}/download Download the exported file once status is ready
GET /api/v1/orgs/{org_id}/traces List trace spans
GET /api/v1/orgs/{org_id}/traces/{trace_id} One trace (full span tree)
GET /api/v1/orgs/{org_id}/incidents Active and recent incidents (rate-limit outages, budget overruns, etc.)
GET /api/v1/orgs/{org_id}/dashboard Dashboard payload
GET /api/v1/orgs/{org_id}/control-center Single-call control-center view (workflows + recent decisions + alerts)
GET /api/v1/orgs/{org_id}/usage Per-key usage breakdown (canonical)
GET /api/v1/orgs/{org_id}/quota Per-key usage breakdown (legacy alias of /usage — same payload)
GET /api/v1/budget/approximate Approximate budget view for UI display — see Budgets → Approximate budget endpoint
GET /api/v1/orgs/{org_id}/status Single-call dashboard status (budget + rate + plan limits + time-to-exhaustion)

Cancellations

POST /api/v1/cancel cancels an in-flight execution. Cancellation is idempotent — calling it twice on the same execution is a no-op and releases the reservation by TTL even if the call never reaches the gateway. See Control plane for the related kill / pause endpoints.

Org management

Method Path Purpose
GET/PATCH/DELETE /api/v1/orgs/{org_id} Org settings, update, delete
GET /api/v1/orgs/{org_id}/api-keys List keys
POST /api/v1/orgs/{org_id}/api-keys Mint key
DELETE /api/v1/orgs/{org_id}/api-keys/{key_id} Revoke key
POST /api/v1/orgs/{org_id}/api-keys/{key_id}/rotate Rotate the HMAC secret in place
GET /api/v1/workflows/{workflow_id}/api-keys Per-workflow key listing
GET /api/v1/orgs/{org_id}/members Members
PATCH /api/v1/orgs/{org_id}/members/{member_id} Update member role
DELETE /api/v1/orgs/{org_id}/members/{member_id} Remove member
POST /api/v1/orgs/{org_id}/invites Invite
DELETE /api/v1/orgs/{org_id}/invites/{invite_id} Revoke invite
POST /api/v1/orgs/{org_id}/invites/{invite_id}/resend Resend invite email
GET /api/v1/invites/{token} Public invite info
POST /api/v1/invites/{token}/accept Public invite accept
POST /api/v1/invites/{token}/decline Public invite decline

Alerts

Method Path Purpose
GET /api/v1/orgs/{org_id}/alerts Active alerts
POST /api/v1/orgs/{org_id}/alerts/{alert_id}/dismiss Dismiss
GET/POST /api/v1/orgs/{org_id}/alert-channels Channels
GET/PATCH /api/v1/orgs/{org_id}/notification-settings Per-user settings

Health

Health endpoints are registered on the gateway's top-level router — they are not under /api/v1. They return 200 OK when healthy, 503 otherwise, with a JSON body listing each dependency's status.

Method Path Purpose
GET /health Alias for /health/live
GET /healthz Alias for /health/live (Kubernetes convention)
GET /health/live Liveness — process is up and accepting connections
GET /health/ready Readiness — Postgres + Redis reachable
GET /health/startup Startup — 200 after migrations complete, 503 while booting

Capabilities

The capabilities endpoint reports the wire-contract version the gateway supports. The SDK calls this on init() to negotiate the protocol version and to surface a startup warning if the SDK is older than what the gateway requires.

Method Path Purpose
GET /api/v1/capabilities Report min_protocol_version / max_protocol_version, sdk_min_version, server version + build timestamp, and the capabilities.* feature flags

When init() detects that the SDK is older than the gateway's required minimum version, it emits a warning so the operator sees the gap before the first /gate call fails with 400 PROTOCOL_TOO_OLD.

The current wire-protocol version is 4 (min supported: 2). init() negotiates the version automatically via /capabilities; you do not need to set anything by hand.

Heartbeat

Long-running workflows post a time-based cadence heartbeat so the gateway can detect an orphaned workflow whose agent process has crashed without sending a kill / pause signal. The recommended cadence is advertised in capabilities.heartbeat_interval_seconds (default 30s).

Method Path Purpose
POST /api/v1/heartbeat Time-based cadence heartbeat; body is { chain_id } only. workflow_id is derived from the API key, not passed in the body.

The SDK posts heartbeats automatically inside the NullRunRuntime background thread once init() has run; operators do not need to call it manually.

WebSocket control plane

Path Purpose
WS /ws/control/{org_id} Real-time kill/pause/policy-invalidated/key-rotated events (HMAC-signed on connect)

Server → client message types: initial_state, state_change, policy_invalidated, key_rotated, resync_required, error, pong, approval_resolved, subscribed.

Client → server message types: ack.

See Control plane for the full protocol and the SDK reaction matrix.

Common request patterns

The examples below use the dashboard's Authorization: Bearer <session-token> header (the token comes from POST /api/v1/auth/login). For SDK-traffic endpoints substitute X-API-Key + HMAC headers — see the Authentication section above.

TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
ORG_ID=8a3b1c7d-...

!!! note "Compute the HMAC signature" For SDK endpoints the X-Signature and X-Signature-Timestamp headers are required. The signature is HMAC-SHA256(secret_key, "<timestamp>:<api_key>:<sha256(body)>"). See Authentication → X-API-Key + HMAC.

Create a workflow

curl -X POST "https://api.nullrun.io/api/v1/orgs/$ORG_ID/workflows" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "production-bot",
    "description": "Customer-facing assistant",
    "budget_cents": 5000,
    "human_approvals_enabled": false
  }'

# → 201 { "id": "wf_abc...", "name": "production-bot", ... }

Mint an API key bound to a workflow

curl -X POST "https://api.nullrun.io/api/v1/orgs/$ORG_ID/workflows/wf_abc.../api-keys" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "prod-bot-key",
    "scopes": ["gate", "track", "verify"]
  }'

# → 201 {
#     "id": "key_...",
#     "key": "nr_live_xxxxxxxxxxxx",   ← shown ONCE, store it
#     "secret_key": "sk_...",          ← shown ONCE, store it
#     "workflow_id": "wf_abc...",
#     "key_prefix": "nr_live_xxxxxx"
#   }

The raw key and secret_key are never returned again — losing them means rotating the key. See API keys → How to create a key.

Kill / pause / resume a running workflow

# Kill — broadcasts state_change(killed) over WS to every connected SDK
curl -X POST "https://api.nullrun.io/api/v1/orgs/$ORG_ID/workflows/wf_abc.../kill" \
  -H "Authorization: Bearer $TOKEN"

# Pause
curl -X POST "https://api.nullrun.io/api/v1/orgs/$ORG_ID/workflows/wf_abc.../pause" \
  -H "Authorization: Bearer $TOKEN"

# Resume
curl -X POST "https://api.nullrun.io/api/v1/orgs/$ORG_ID/workflows/wf_abc.../resume" \
  -H "Authorization: Bearer $TOKEN"

Single-call status (current spend / budget / time-to-exhaustion)

curl "https://api.nullrun.io/api/v1/orgs/$ORG_ID/status" \
  -H "Authorization: Bearer $TOKEN"

# → 200 {
#     "current_spend_cents": 2340,
#     "budget_cents": 5000,
#     "time_to_exhaustion_secs": 86400,
#     "rate_used": 12,
#     "rate_limit_per_min": 60,
#     "plan_caps": { ... }
#   }

Useful for dashboards and alerts — one call returns everything you need to show "you've used X of Y".

See also