API Reference

REST API endpoints for license management, policy distribution, and audit collection.

Endpoints#

MethodPathDescription
GET/api/licenseGet or issue license
POST/api/license/refreshForce-refresh license
GET/api/policyList policies
POST/api/policyCreate policy
GET/api/policy/:idGet policy by ID
PUT/api/policy/:idUpdate policy
DELETE/api/policy/:idSoft-delete policy
GET/api/policy/fetchFetch active YAML
GET/api/auditQuery audit events
POST/api/audit/ingestIngest audit events
GET/api/keysList API keys
POST/api/keysCreate API key
DELETE/api/keys/:idRevoke API key
GET/api/admin/membersList members
PATCH/api/admin/members/:idChange member role

Authentication#

API requests are authenticated with Bearer tokens. Web dashboard uses session cookies. CLI uses API keys with the Authorization: Bearer tirith_... header.

shell
# Bearer token authentication
$ curl -H "Authorization: Bearer tirith_sk_..." \
https://api.tirith.sh/api/license

License#

GET/api/license

Get or issue a license key for the authenticated user's org.

Auth:Session / API Key

Returns the signed license token and expiry. Creates a new one if none exists or the current one is expired.

response.json
{
"token": "eyJhbGciOiJFZDI1NTE5...",
"expires_at": "2026-03-21T00:00:00Z",
"tier": "pro",
"org_id": "org_abc123"
}
POST/api/license/refresh

Force-refresh the license key for the org.

Auth:Session / API Key
shell
$ curl -X POST \
-H "Authorization: Bearer tirith_sk_..." \
https://api.tirith.sh/api/license/refresh
response.json
{
"token": "eyJhbGciOiJFZDI1NTE5...",
"expires_at": "2027-03-21T00:00:00Z",
"tier": "pro",
"org_id": "org_abc123",
"refreshed": true
}

Policy#

GET/api/policy

List all policies for the org.

Auth:Session / API KeyTier:Team+
shell
$ curl -H "Authorization: Bearer tirith_sk_..." \
https://api.tirith.sh/api/policy
response.json
{
"policies": [
{
"id": "pol_a1b2c3",
"name": "default-security",
"version": 3,
"active": true,
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-03-01T14:22:00Z"
}
]
}
POST/api/policy

Create a new policy.

Auth:Session (admin/owner)Tier:Team+
shell
$ curl -X POST \
-H "Authorization: Bearer tirith_sk_..." \
-H "Content-Type: application/json" \
-d '{
"name": "ci-pipeline-policy",
"yaml": "rules:\n - id: no-exec\n pattern: exec\n severity: critical"
}' \
https://api.tirith.sh/api/policy
response.json
{
"id": "pol_d4e5f6",
"name": "ci-pipeline-policy",
"version": 1,
"active": true,
"created_at": "2026-03-21T08:15:00Z"
}
error 422 - validation error
{
"error": "validation_error",
"message": "Invalid policy YAML",
"details": [
"rules[0].severity must be one of: critical, high, medium, low"
]
}
GET/api/policy/:id

Get a specific policy including YAML content.

Auth:Session / API KeyTier:Team+
shell
$ curl -H "Authorization: Bearer tirith_sk_..." \
https://api.tirith.sh/api/policy/pol_a1b2c3
response.json
{
"id": "pol_a1b2c3",
"name": "default-security",
"version": 3,
"active": true,
"yaml": "rules:\n - id: no-exec\n pattern: exec\n severity: critical\n - id: no-eval\n pattern: eval\n severity: high",
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-03-01T14:22:00Z"
}
error 404 - not found
{
"error": "not_found",
"message": "Policy pol_invalid not found"
}
PUT/api/policy/:id

Update a policy. Increments version automatically.

Auth:Session (admin/owner)Tier:Team+
shell
$ curl -X PUT \
-H "Authorization: Bearer tirith_sk_..." \
-H "Content-Type: application/json" \
-d '{
"name": "default-security",
"yaml": "rules:\n - id: no-exec\n pattern: exec\n severity: critical\n - id: no-eval\n pattern: eval\n severity: high\n - id: no-unsafe-regex\n pattern: RegExp\n severity: medium"
}' \
https://api.tirith.sh/api/policy/pol_a1b2c3
response.json
{
"id": "pol_a1b2c3",
"name": "default-security",
"version": 4,
"active": true,
"updated_at": "2026-03-21T09:00:00Z"
}
DELETE/api/policy/:id

Soft-delete a policy (sets active=false).

Auth:Session (admin/owner)Tier:Team+
shell
$ curl -X DELETE \
-H "Authorization: Bearer tirith_sk_..." \
https://api.tirith.sh/api/policy/pol_a1b2c3
response.json
{
"id": "pol_a1b2c3",
"active": false,
"deleted_at": "2026-03-21T09:05:00Z"
}
GET/api/policy/fetch

Fetch the active policy YAML for CLI consumption.

Auth:API KeyTier:Team+

Returns raw YAML content. Used by the CLI to pull the latest active policy.

shell
$ curl -H "Authorization: Bearer tirith_sk_..." \
https://api.tirith.sh/api/policy/fetch
response.yaml
rules:
- id: no-exec
pattern: exec
severity: critical
- id: no-eval
pattern: eval
severity: high

Audit#

GET/api/audit

Query audit events with pagination and filtering.

Auth:Session (admin/owner)Tier:Team+

Query params: since, until, action, rule_id, session_id, page, limit (max 200).

shell
$ curl -H "Authorization: Bearer tirith_sk_..." \
"https://api.tirith.sh/api/audit?since=2026-03-01&action=block&limit=10"
response.json
{
"events": [
{
"id": "evt_x7y8z9",
"action": "block",
"rule_id": "no-exec",
"session_id": "sess_abc123",
"timestamp": "2026-03-20T16:45:12Z",
"metadata": {
"file": "src/utils.ts",
"line": 42,
"agent": "claude-code"
}
}
],
"page": 1,
"total": 1
}
POST/api/audit/ingest

Ingest audit events from CLI clients.

Auth:API KeyTier:Team+
shell
$ curl -X POST \
-H "Authorization: Bearer tirith_sk_..." \
-H "Content-Type: application/json" \
-d '{
"events": [
{
"action": "block",
"rule_id": "no-exec",
"session_id": "sess_abc123",
"timestamp": "2026-03-20T16:45:12Z",
"metadata": { "file": "src/utils.ts", "line": 42 }
}
]
}' \
https://api.tirith.sh/api/audit/ingest
response.json
{
"ingested": 1,
"status": "ok"
}
error 401 - unauthorized
{
"error": "unauthorized",
"message": "Invalid or expired API key"
}

API Keys#

GET/api/keys

List all non-revoked API keys for the org (prefix only, never the hash).

Auth:Session
shell
$ curl -H "Cookie: session=..." \
https://api.tirith.sh/api/keys
response.json
{
"keys": [
{
"id": "key_m1n2o3",
"prefix": "tirith_sk_a1b2...",
"label": "CI Pipeline",
"created_at": "2026-02-10T12:00:00Z",
"last_used_at": "2026-03-20T08:30:00Z"
}
]
}
POST/api/keys

Create a new API key. Returns the raw key once. Max 10 per org.

Auth:Session

The full key is only returned once at creation. Store it securely.

shell
$ curl -X POST \
-H "Cookie: session=..." \
-H "Content-Type: application/json" \
-d '{ "label": "staging-deploy" }' \
https://api.tirith.sh/api/keys
response.json
{
"id": "key_p4q5r6",
"key": "tirith_sk_live_a1b2c3d4e5f6g7h8...",
"prefix": "tirith_sk_live_a1b2...",
"label": "staging-deploy",
"created_at": "2026-03-21T10:00:00Z"
}
DELETE/api/keys/:id

Revoke an API key (soft-delete). Must belong to your org.

Auth:Session
shell
$ curl -X DELETE \
-H "Cookie: session=..." \
https://api.tirith.sh/api/keys/key_m1n2o3
response.json
{
"id": "key_m1n2o3",
"revoked": true,
"revoked_at": "2026-03-21T10:05:00Z"
}

Members#

GET/api/admin/members

List org members.

Auth:Session (admin/owner)Tier:Team+
shell
$ curl -H "Cookie: session=..." \
https://api.tirith.sh/api/admin/members
response.json
{
"members": [
{
"id": "usr_j1k2l3",
"email": "[email protected]",
"role": "owner",
"joined_at": "2026-01-01T00:00:00Z"
},
{
"id": "usr_m4n5o6",
"email": "[email protected]",
"role": "member",
"joined_at": "2026-02-15T09:30:00Z"
}
]
}
PATCH/api/admin/members/:id

Change a member's role. Only owners can change roles.

Auth:Session (owner)Tier:Team+
shell
$ curl -X PATCH \
-H "Cookie: session=..." \
-H "Content-Type: application/json" \
-d '{ "role": "admin" }' \
https://api.tirith.sh/api/admin/members/usr_m4n5o6
response.json
{
"id": "usr_m4n5o6",
"email": "[email protected]",
"role": "admin",
"updated_at": "2026-03-21T11:00:00Z"
}
error 403 - forbidden
{
"error": "forbidden",
"message": "Insufficient permissions. Owner role required."
}