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
| Section | Operations | What it covers |
|---|---|---|
| Health | 1 | Liveness. |
| Directory | 5 | Public, cacheable domain directory. |
| Resolution | 2 | Signed workload trust assertions and the keys that verify them. |
| Changes | 1 | Public lifecycle feed for relying parties. |
| Bundles | 1 | Approved, immutable SPIFFE trust bundles. |
| Auth | 10 | Sign-in, sessions and passkeys. |
| Organizations | 18 | Organizations, members, invitations and service tokens. |
| Claims | 10 | Domain claims, DNS challenges, evidence, appeals and jobs. |
| Recovery | 9 | Organization recovery with a fresh DNS recheck and two independent reviewers. |
| Issuer bindings | 9 | Issuer registration, the issuer-control ceremony, rotation and withdrawal. |
| Delegations | 5 | Delegation of subdomains to other organizations. |
| Documentation | 1 | This 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 with415(invalid_request). Unknown JSON fields are rejected with afield_errorsentry (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 exampleorg_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
404not_foundin the error model for/v1/,/auth/,/internal/and/.well-known/. - Alias hostnames answer
301(GET and HEAD) or308(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 thex-art-csrfheader (thecsrf_tokenfromGET /auth/session) and anOriginheader 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) return401 step_up_requireduntil 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 noOriginheader skips the origin check; one that sendsOriginmust still match. A presented but invalidAuthorizationheader is401, never a cookie fallback. Operations marked human-only refuse service tokens with403.
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
| Scheme | Shown as | Details |
|---|---|---|
sessionCookie | Session (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."). |
sessionNoMfa | Session, before the passkey step | The 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. |
sessionStepUp | Session 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. |
serviceToken | Service token | A 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. |