Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.vane.build/llms.txt

Use this file to discover all available pages before exploring further.

POST /v1/companies

Creates a new company tenant. Generates an Ed25519 key pair, an empty attestation chain, and a bootstrap API key. No authentication required. Returns 409 if a company with this companyId already exists. Also available as POST /v1/setup — identical behavior, kept for backward compatibility.

Request body

FieldTypeRequiredDescription
companyIdstringYesPermanent, unique identifier for this company. Used in SPIFFE IDs and as the tenant key.
metadataobjectNoArbitrary JSON metadata stored with the company record.

Response 201

FieldTypeDescription
companyIdstringThe company identifier.
spiffeIdstringSPIFFE ID: spiffe://{trustDomain}/company/{companyId}
registeredAtstringISO 8601 timestamp.
apiKeystringBootstrap API key (prefix: counsel_). Shown once — save immediately.

Error responses

StatusBodyMeaning
400{ "error": "Missing or invalid field: companyId is required" }companyId is missing or not a string.
409{ "error": "Company already exists: acme" }A company with this ID is already registered.

Example

curl -s -X POST http://localhost:3000/v1/companies \
  -H "Content-Type: application/json" \
  -d '{ "companyId": "acme", "metadata": { "plan": "enterprise" } }'
{
  "companyId": "acme",
  "spiffeId": "spiffe://vane.local/company/acme",
  "registeredAt": "2026-01-01T00:00:00.000Z",
  "apiKey": "counsel_a1b2c3d4e5f67890..."
}

GET /v1/company

Returns the authenticated company’s own record. Useful for validating an API key and retrieving metadata. Requires authentication.

Response 200

FieldTypeDescription
companyIdstringThe company identifier.
spiffeIdstringThe company’s SPIFFE ID.
registeredAtstringISO 8601 registration timestamp.
metadataobjectPresent only if metadata was set at registration.

Example

curl -s http://localhost:3000/v1/company \
  -H "Authorization: Bearer $API_KEY"
{
  "companyId": "acme",
  "spiffeId": "spiffe://vane.local/company/acme",
  "registeredAt": "2026-01-01T00:00:00.000Z",
  "metadata": { "plan": "enterprise" }
}

POST /v1/recover-key

Emergency key recovery. Returns the first API key created for a company. Localhost-only — remote callers receive 403. No authentication required. This endpoint is a safety hatch for when you lose your API key. In production, restrict access to it at the network level (firewall, VPC) rather than relying solely on the IP check.

Request body

FieldTypeRequiredDescription
companyIdstringYesThe company whose key to recover.

Response 200

FieldTypeDescription
keystringThe API key.
labelstring | nullThe key’s label (usually "bootstrap" for the first key).
createdAtstringISO 8601 creation timestamp.

Error responses

StatusBodyMeaning
400{ "error": "companyId is required" }Missing or invalid companyId.
403{ "error": "Forbidden" }Called from a non-localhost IP.
404{ "error": "No API keys found for company: acme" }Company has no API keys.

Example

# Must be called from localhost
curl -s -X POST http://localhost:3000/v1/recover-key \
  -H "Content-Type: application/json" \
  -d '{ "companyId": "acme" }'
{
  "key": "counsel_a1b2c3d4...",
  "label": "bootstrap",
  "createdAt": "2026-01-01T00:00:00.000Z"
}

POST /v1/companies/svid

Issues a JWT-SVID for the authenticated company’s identity. The resulting token is used as the subject_token in a full RFC 8693 token exchange. Requires authentication.

Response 200

FieldTypeDescription
companyIdstringThe company identifier.
spiffeIdstringThe company’s SPIFFE ID.
svidstringJWT-SVID signed with the company’s Ed25519 key. TTL: 3600 s.

Example

curl -s -X POST http://localhost:3000/v1/companies/svid \
  -H "Authorization: Bearer $API_KEY"
{
  "companyId": "acme",
  "spiffeId": "spiffe://vane.local/company/acme",
  "svid": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImExYjJjM2Q0In0..."
}