Keel API Reference v0.2.4

Keel Cloud is a REST API for structural safety in autonomous AI agent systems. Policy enforcement, cryptographic audit trails, and approval gates -- accessible from any client that speaks HTTP. The dashboard is a reference client. Build your own, or use ours.

Authentication

All tenant endpoints require a Bearer token in the Authorization header. This is the API key returned at registration.

curl -H "Authorization: Bearer YOUR_API_KEY" \ https://api.thresholdsignalworks.com/api/v1/status
API keys are shown once at registration and cannot be recovered. Store yours securely. If lost, contact support for a key rotation.

Two auth levels exist:

LevelAccessHeader
PublicRegistration, health checkNone required
TenantAll /api/v1/ endpointsBearer {tenant_api_key}

Base URL

https://api.thresholdsignalworks.com

All tenant-facing endpoints are prefixed with /api/v1/. Webhooks use /webhooks/.

Error Handling

Errors return JSON with a detail field describing the issue.

{ "detail": "Invalid API key." }
200 Success
400 Bad request -- invalid parameters
401 Unauthorised -- missing or invalid API key
402 Payment required -- tenant has no active subscription
404 Not found
409 Conflict -- duplicate resource (e.g. email already registered)
422 Validation error -- invalid field values
500 Internal server error

Register

POST /api/v1/register Public

Create a new tenant account. Returns the API key exactly once. The tenant starts with pending billing status -- subscribe via the billing endpoints to activate full API access.

Request body

FieldTypeDescription
email requiredstringAccount email address
name optionalstringDisplay name or organisation

Example

curl -X POST https://api.thresholdsignalworks.com/api/v1/register \ -H "Content-Type: application/json" \ -d '{"email": "[email protected]", "name": "Dev Team"}'

Response

{ "tenant_id": "f6d27607-ce9d-485d-8b29-c80e80a22d66", "api_key": "keel_a1b2c3d4e5f6...", "message": "Save this API key securely. It will not be shown again." }
Store the API key immediately. It cannot be retrieved after this response. Use it to authenticate all subsequent requests.

Billing

Billing endpoints bypass the entitlement gate -- tenants with pending or cancelled status can access these to subscribe or manage their subscription.

GET /api/v1/billing/status Tenant

Returns the tenant's current billing state.

Response

{ "tenant_id": "f6d27607-...", "plan": "starter", "billing_status": "active", "entitlement_expires_at": null, "external_customer_id": "cus_XxXxXxXXX", "last_billing_sync_at": "2026-03-08T00:23:14.728966+00:00", "active": true }
POST /api/v1/billing/checkout Tenant

Creates a Stripe Checkout session. Redirect the user to the returned URL to complete payment.

Request body

FieldTypeDescription
plan requiredstring"starter" (Pro, €29/mo) or "professional" (Team, €149/mo)

Response

{ "checkout_url": "https://checkout.stripe.com/c/pay/...", "checkout_session_id": "cs_live_xxXxXxX..." }
POST /api/v1/billing/portal Tenant

Creates a Stripe Customer Portal session for managing subscription, payment methods, and invoices. Requires an existing Stripe customer ID (set after first payment).

Response

{ "portal_url": "https://billing.stripe.com/p/session/..." }

Status

GET /api/v1/status Tenant

Returns the tenant's current system state: policy count, WAL event count, snapshot hash.

Response

{ "tenant_id": "cf4de715-...", "policy_count": 5, "policy_count_active": 5, "policy_snapshot_hash": "64a3303fc7db...", "policy_store_version": 2, "wal_event_count": 3, "wal_last_event": null, "quarantine_count": 0 }

Policies

GET /api/v1/policies Tenant

Returns all policies for the tenant.

Response

// Returns an array of policy objects [ { "id": "sys_c74ef1ddfe77", "scope": "global", "type": "constraint", "priority": 0, "content": "No irreversible action without explicit structured authorisation", "source": "system_default", "active": true, "created_at": "2026-03-05T17:48:00.212898+00:00", "deactivated_at": null, "metadata": {} } ]
POST /api/v1/policies Tenant

Create a new policy.

Request body

FieldTypeDescription
id requiredstringUnique policy identifier
content requiredstringPlain-language rule description
scope requiredstringglobal, gmail, gcal, github, or filesystem
type requiredstringconstraint, permission, limit, or preference
priority requiredinteger0 (highest) to 2 (lowest)
source requiredstringuser_explicit or user_inferred

Example

curl -X POST https://api.thresholdsignalworks.com/api/v1/policies \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "id": "no-email-delete", "content": "Never delete emails from [email protected]", "scope": "gmail", "type": "constraint", "priority": 0, "source": "user_explicit" }'
GET /api/v1/policies/{policy_id} Tenant

Returns a single policy by ID.

DELETE /api/v1/policies/{policy_id} Tenant

Deactivates a policy. Sets deactivated_at and active to false.

POST /api/v1/policies/check Tenant

Evaluate an action against all active policies. Returns whether the action is allowed, the risk level, and any violations.

Request body

{ "action_type": "send_email", "target_ids": ["[email protected]"], "surface": "gmail", "reversibility": "irreversible" }

Response

{ "passed": true, "action_id": "0beb5d87aca1...", "risk_level": 0, "violations": [], "fidelity_ok": true, "reasons": [] }
GET /api/v1/policies/snapshot Tenant

Returns the current policy store snapshot hash for integrity verification.

Write-Ahead Log (WAL)

GET /api/v1/wal Tenant

Returns all WAL events for the tenant. Each event is cryptographically chained to the previous via SHA-256 hashes.

Response

// Returns an array of WAL events [ { "event_type": "policy_check", "payload": { "action_type": "read_email", "passed": true, "risk_level": 0 }, "timestamp": "2026-03-06T13:04:45.684433+00:00", "session_id": "default", "prev_hash": "ad6514809779...", "event_hash": "f35af87f5034..." } ]
POST /api/v1/wal Tenant

Append a new event to the WAL. The server computes the hash chain automatically.

Request body

FieldTypeDescription
event_type requiredstringEvent classification (e.g. PROPOSED, APPROVED, BLOCKED)
payload requiredobjectEvent data -- action details, results, metadata
session_id optionalstringAgent session identifier (default: "default")
GET /api/v1/wal/verify Tenant

Verify the integrity of the entire WAL hash chain. Returns whether the chain is valid, the event count, and the chain tip hash.

Response

{ "valid": true, "event_count": 3, "chain_tip": "f35af87f5034...", "message": "Chain integrity verified." }
GET /api/v1/wal/tip Tenant

Returns the latest WAL event hash without verifying the full chain. Useful for quick sync checks.

Agents

GET /api/v1/agents Tenant

Returns all agent sessions that have interacted with this tenant's workspace.

PUT /api/v1/agents/{session_id} Tenant

Update metadata for an agent session.

Quarantine

GET /api/v1/quarantine Tenant

Returns all quarantined items.

POST /api/v1/quarantine Tenant

Quarantine an item (move to safe holding instead of deletion).

POST /api/v1/quarantine/{item_id}/release Tenant

Release an item from quarantine.

Export

GET /api/v1/export Tenant

Download a compliance-ready audit export. Set the Accept header to application/json or text/csv to control format.

Example

curl -H "Authorization: Bearer YOUR_API_KEY" \ -H "Accept: text/csv" \ https://api.thresholdsignalworks.com/api/v1/export \ -o keel-audit.csv

Webhooks

POST /webhooks/stripe Stripe Only

Receives Stripe webhook events. Validates the Stripe-Signature header against the configured webhook secret. Handles checkout.session.completed (activates tenant), customer.subscription.updated (status changes), and customer.subscription.deleted (cancellation). Events are deduplicated by event ID.

This endpoint is called by Stripe, not by your application. Do not send requests to it directly.

Plans and Pricing

PlanAPI NamePriceFeatures
Local--FreeCLI and SKILL.md only. No Cloud API access.
Prostarter€29/month1 workspace, 10 agents, policy sync, dashboard, WAL, 90-day retention
Teamprofessional€149/monthShared workspace, 3 seats, shared policies, exports, 365-day retention
Business--ContactMultiple workspaces, RBAC, DPA, custom retention. Contact sales
Plan names in the API use internal identifiers: starter (Pro) and professional (Team). These are the values passed to the checkout endpoint.

Rate Limits

API requests are rate-limited per tenant. Current limits are generous for launch. If you encounter 429 responses, reduce request frequency. Specific limits will be published as usage patterns stabilise.

SDKs and Integrations

The threshold-keel CLI (PyPI) wraps this API. Install with:

pip install threshold-keel

The CLI handles authentication, local WAL caching, cloud sync, and policy evaluation. Set KEEL_CLOUD_API_KEY in your environment to enable Cloud mode.

For agent integration, see the SKILL.md in the Keel repository.

Threshold Signalworks Ltd — Registered in Ireland · Privacy · Terms