Preview — not for production reliance
Documentation

Docs API reference

API reference

Every public and organization endpoint of the directory, generated from its OpenAPI description.

Generated from /v1/openapi.yaml, the OpenAPI 3.1.0 description of the public and organization API (version 0.1.0). Base URL: https://svid.io.

Sections

SectionOperationsWhat it covers
Health1Liveness.
Directory5Public, cacheable domain directory.
Resolution2Signed workload trust assertions and the keys that verify them.
Changes1Public lifecycle feed for relying parties.
Bundles1Approved, immutable SPIFFE trust bundles.
Auth10Sign-in, sessions and passkeys.
Organizations18Organizations, members, invitations and service tokens.
Claims10Domain claims, DNS challenges, evidence, appeals and jobs.
Recovery9Organization recovery with a fresh DNS recheck and two independent reviewers.
Issuer bindings9Issuer registration, the issuer-control ceremony, rotation and withdrawal.
Delegations5Delegation of subdomains to other organizations.
Documentation1This document.

Powered by Sectigo. Preview — not for production reliance.

Agentic Root Trust is a public directory that connects a SPIFFE workload identity (a trust domain) to the organization that stands behind it. Relying parties resolve a trust domain and receive a short-lived signed assertion plus a pointer to the approved public trust bundle. Organizations use the authenticated half of this API (the same API the console uses) to register, prove domain control, submit evidence, register issuers and delegate subdomains.

The directory never issues credentials and never holds private keys. A resolution is a statement of what the directory knows, not an authorization decision: the relying party always makes the final decision.

This document covers the public and organization APIs. Internal reviewer and operator routes are in openapi-internal.yaml.

Conventions

  • All bodies are JSON (Content-Type: application/json) unless a route says otherwise. Any other declared content type on a mutation is refused with 415 (invalid_request). Unknown JSON fields are rejected with a field_errors entry (unknown field) on every authenticated mutation.
  • Timestamps are ISO 8601 UTC strings. Record ids are opaque: a short prefix, an underscore and 26 to 32 characters of [0-9a-z] (for example org_7k3m9q2x8d5f1h4j6n0p2r4t8v).
  • Every response, including errors and redirects, carries x-request-id. Quote it when reporting a problem.
  • A path that matches no route (or a known path with the wrong method) answers 404 not_found in the error model for /v1/, /auth/, /internal/ and /.well-known/.
  • Alias hostnames answer 301 (GET and HEAD) or 308 (everything else) to the canonical host, keeping path and query.

Errors

Every failure is { "code", "message", "request_id", "field_errors"? }. code is machine readable; message is for people. The HTTP status follows the code:

code status
invalid_request 400 (413 for an oversized body, 415 for the wrong content type)
unauthenticated 401
step_up_required 401
forbidden 403
not_found 404
conflict 409
semantic_check_failed 422
rate_limited 429
provider_unavailable 503
unavailable 503

Unknown, other-tenant and not-visible records answer the same 404, so tenants cannot be enumerated.

Authentication

  • Public: directory reads, resolution, the change feed, JWKS and bundles need no credentials.
  • Session (sessionCookie): a browser session cookie issued after sign-in (GitHub, Google) and a passkey assertion (MFA). Every mutation also needs the x-art-csrf header (the csrf_token from GET /auth/session) and an Origin header equal to the directory origin.
  • Step-up (sessionStepUp): a session whose passkey assertion is at most 300 seconds old. Sensitive actions (issuer activation, delegation, membership and role changes, service tokens, credential changes) return 401 step_up_required until the person re-runs the passkey assertion (POST /auth/passkeys/authentication/*). Service tokens can never step up.
  • Service token (serviceToken): Authorization: Bearer <token> for server-to-server clients, scoped to one organization and a subset of roles. A bearer request that sends no Origin header skips the origin check; one that sends Origin must still match. A presented but invalid Authorization header is 401, never a cookie fallback. Operations marked human-only refuse service tokens with 403.

Idempotency

Every /v1 mutation except the binary evidence upload requires an Idempotency-Key header (1 to 255 characters of A-Z a-z 0-9 . _ : -). Records are kept for 24 hours per principal. Replaying the same key with the same request returns the stored status and body with idempotency-replayed: true; the same key with a different request is 409 conflict; a request still in flight is 409 conflict. Only 2xx responses and the deterministic client errors 400, 404, 409 and 422 are stored, so a 401 step_up_required, 403, 429 or 5xx can be retried with the same key. One-time secrets (challenge values, service-token secrets, upload tokens) are shown once and are redacted in a replay. Mutation bodies are limited to 64 KiB.

Caching

Resource cache-control
GET /v1/resolve (all responses, errors included) no-store
GET /v1/issuer-bindings/{id}/versions/{version}/bundle (200 and 304) public, max-age=31536000, immutable
GET /v1/changes public, max-age=10
GET /v1/domains, GET /v1/domains/{domain} public, max-age=60
GET /.well-known/jwks.json public, max-age=300
GET /v1/openapi.yaml public, max-age=3600
Responses carrying one-time secrets, GET /auth/session, GET /auth/providers, OIDC redirects no-store

Servers

  • https://svid.io: Production (preview)
  • https://art-directory-staging.ihassard.workers.dev: Staging (the test identity provider is enabled here)

Security schemes

SchemeShown asDetails
sessionCookieSession (passkey-verified)Browser session cookie (HttpOnly, Secure, SameSite=Lax, 12-hour lifetime) for a principal that has completed a passkey assertion (MFA). Every mutation also needs x-art-csrf and an Origin equal to the directory origin. Without MFA the response is 401 unauthenticated ("Passkey verification required.").
sessionNoMfaSession, before the passkey stepThe same session cookie, accepted before the passkey ceremony: used only for GET /auth/session, POST /auth/logout and the passkey registration and assertion endpoints. Mutations still need x-art-csrf and a matching Origin.
sessionStepUpSession with step-up (passkey within 300 s)The same session cookie, whose last passkey assertion (mfa_at) is at most 300 seconds old. Otherwise the response is 401 step_up_required; re-run POST /auth/passkeys/authentication/* and retry (the same Idempotency-Key may be reused). Service tokens can never satisfy this scheme.
serviceTokenService tokenA service token created by an organization owner (POST /v1/organizations/{id}/service-tokens). Scoped to one organization and to a subset of issuer_administrator, domain_administrator and viewer. Never an owner, never human-only operations, never step-up. Expires after at most 90 days.