Core API - overview and authentication

Base URL, versioning, and the two authentication models: API key for agents, session for the dashboard and integrators.

3 min read · verified against [email protected]

The Core API is the single HTTP surface that guard-agent instances and the dashboard both talk to. Everything documented in the reference section lives under one base URL and one versioned prefix.

Base URL and versioning

All endpoints share a single base URL and are mounted under the /api/v1 prefix:

https://api.guard-core.com/api/v1

The prefix is defined once in backend/guard-core-api/guard_core_api/app.py and applied to every router at startup. All paths in the Agent Telemetry API therefore start with /api/v1.

Every response carries an API-Version header set to the running release's CalVer build (for example 2026.08.28.3). The dashboard captures the first value it sees after a page load and only prompts for a refresh when a later response reports a different one.

Two authentication models

The API exposes two distinct surfaces, agent ingestion and session-authenticated management, and each uses a different credential mechanism:

SurfaceCredentialHeader
Agent ingestion (events, metrics, status, rules)Project API keyX-API-Key
Dashboard and integrator (projects, keys, encryption)Session JWT (cookie or Authorization bearer)Set by fastapi-users

Never mix the two: sending an API key to a session endpoint returns 401. On an ingestion endpoint, omitting the X-API-Key header entirely returns 422 because the header is required, while sending session credentials (or any invalid value in X-API-Key) returns 401 because the telemetry router validates the key directly.

API key auth (agents)

Ingestion endpoints require an X-API-Key header whose value is a project-scoped API key. An optional X-Project-Id header disambiguates when one key covers multiple projects, but is not required if the key already maps to a single project.

The key is validated by authenticate_telemetry_project in guard_core_api/services/telemetry_service.py, which delegates to verify_api_key in guard_core_api/services/api_keys_service.py. An invalid or missing key raises HTTP 401 Unauthorized immediately, before any other processing occurs.

Session auth (dashboard and integrators)

The SaaS dashboard authenticates via a session obtained at login. This session surface exists to power the dashboard UI. Operations such as managing projects, issuing or revoking API keys, and rotating per-project encryption are performed through the dashboard rather than by scripting against raw endpoints.

The public, documented programmatic surface is the agent telemetry API only. Agents authenticate with an X-API-Key header (see the section above); they do not use session credentials.

Rate limits and quotas

Ingestion (write) endpoints are protected by at least one layer of rate limiting. Read-only endpoints such as GET /api/v1/status carry no rate-limit bucket:

  • Per-IP burst bucket - applied on ingestion endpoints before the API key is verified. If the sending IP exhausts its token bucket the server returns 429 Too Many Requests with a Retry-After header.
  • Per-API-key bucket - capacity varies by organization tier (individual, pro, team, business, enterprise).
  • Per-project bucket - a second sliding window scoped to the project, also tier-dependent.
  • Session endpoint rate limits - session-authenticated endpoints are rate-limited by guard's @rate_limit decorator (typically 10-30 requests per 60-second window).

When an agent receives a 429 it should not drop the payload. The agent buffering guide explains the retry and back-off strategy guard-agent uses to survive rate-limit windows without losing events.

How this reference stays accurate

The API catalog at frontend/src/content/docs/_generated/api-catalog.json is generated directly from the live FastAPI OpenAPI schema by running scripts/emit_api_catalog.py in the backend. CI regenerates the catalog on every push and fails the build if the committed file drifts from the live schema.

Every api-endpoint HTML comment in these reference docs is checked by npm run lint:docs:api-catalog against that catalog. If a documented path no longer exists in the API, the lint fails and the doc must be updated before the branch can merge. This makes the reference docs machine-checked rather than trust-based.