Skill Registry
The Skill Registry is the central catalog of all skills available in a Horizon deployment. Every skill that an agent can execute is registered here with its metadata, parameter schema, category, and version. The registry API provides read-only access for discovering skills programmatically.
How the Skill Registry Works
Section titled “How the Skill Registry Works”Skills in Horizon are stored in a skills table in Supabase. Each skill is uniquely identified by a composite key of three fields:
| Column | Type | Description |
|---|---|---|
category | text | The integration or functional grouping (e.g., quickbooks, sage-intacct, web, platform). |
skill_name | text | The skill identifier in kebab-case (e.g., profit-and-loss-report, query-customer). |
version | text | The version string (e.g., v1.0, v2.0). |
A composite unique constraint on (category, skill_name, version) ensures that no two skills share the same combination. This allows multiple versions of the same skill to coexist, enabling gradual migration without breaking existing integrations.
Skills Table Structure
Section titled “Skills Table Structure”The full skills table includes these columns:
| Column | Type | Description |
|---|---|---|
id | uuid | Auto-generated primary key. |
category | text | Skill category / integration name. |
skill_name | text | Kebab-case skill identifier. |
version | text | Skill version string. |
display_name | text | Human-readable skill name shown in the UI. |
description | text | A description of what the skill does. |
parameters_schema | jsonb | JSON Schema defining the skill’s input parameters. |
output_schema | jsonb | JSON Schema describing the skill’s output structure. |
required_scopes | text[] | API key scopes required to execute this skill. |
is_active | boolean | Whether the skill is currently available for execution. |
created_at | timestamptz | When the skill was registered. |
updated_at | timestamptz | When the skill metadata was last modified. |
Skill Discovery
Section titled “Skill Discovery”When an agent executes a skill via POST /api/{category}/{version}/{skill-name}, the Express backend resolves the skill by looking up the (category, skill_name, version) tuple in the registry. If no matching active skill is found, the API returns a 404 skill_not_found error.
The registry endpoints described below let you discover what skills are available before attempting to execute them.
List Skills
Section titled “List Skills”/api/skills List all active skills in the registry, optionally filtered by category.
Requires authentication via x-api-key header.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| category | string | Filter skills by category (e.g., 'quickbooks', 'web'). Returns all categories if omitted. |
Request
Section titled “Request”curl -X GET "https://api.horizonplatform.ai/api/skills?category=quickbooks" \ -H "x-api-key: hz_live_abc123def456"const params = new URLSearchParams({ category: 'quickbooks' });
const response = await fetch( `https://api.horizonplatform.ai/api/skills?${params}`, { headers: { 'x-api-key': 'hz_live_abc123def456' } });
const skills = await response.json();console.log(`Found ${skills.length} skills`);import requests
response = requests.get( 'https://api.horizonplatform.ai/api/skills', headers={'x-api-key': 'hz_live_abc123def456'}, params={'category': 'quickbooks'})
skills = response.json()print(f"Found {len(skills)} skills")Response
Section titled “Response”// 200 OK[ { "id": "sk_001", "category": "quickbooks", "skill_name": "profit-and-loss-report", "version": "v1.0", "display_name": "Profit & Loss Report", "description": "Generate a Profit & Loss report from QuickBooks Online for a specified date range and accounting method.", "required_scopes": ["quickbooks"], "is_active": true, "created_at": "2026-01-15T10:00:00Z", "updated_at": "2026-03-01T08:30:00Z" }, { "id": "sk_002", "category": "quickbooks", "skill_name": "query-customer", "version": "v1.0", "display_name": "Query Customer", "description": "Look up customer details in QuickBooks Online by name, email, or ID.", "required_scopes": ["quickbooks"], "is_active": true, "created_at": "2026-01-15T10:00:00Z", "updated_at": "2026-02-20T14:15:00Z" }, { "id": "sk_003", "category": "quickbooks", "skill_name": "balance-sheet", "version": "v1.0", "display_name": "Balance Sheet", "description": "Generate a Balance Sheet report from QuickBooks Online as of a specified date.", "required_scopes": ["quickbooks"], "is_active": true, "created_at": "2026-02-01T09:00:00Z", "updated_at": "2026-02-01T09:00:00Z" }]Listing All Categories
Section titled “Listing All Categories”To discover all available categories, call the list endpoint without a category filter:
curl -X GET https://api.horizonplatform.ai/api/skills \ -H "x-api-key: hz_live_abc123def456"The response includes skills from all categories. You can extract unique categories client-side, or use the response to build a skill browser in your application.
Get Skill Metadata
Section titled “Get Skill Metadata”/api/skills/:category/:version/:skillName Retrieve full metadata for a specific skill, including its parameter schema and output schema.
Requires authentication via x-api-key header.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| category required | string | The skill category (e.g., 'quickbooks'). |
| version required | string | The skill version (e.g., 'v1.0'). |
| skillName required | string | The skill name in kebab-case (e.g., 'profit-and-loss-report'). |
Request
Section titled “Request”curl -X GET https://api.horizonplatform.ai/api/skills/quickbooks/v1.0/profit-and-loss-report \ -H "x-api-key: hz_live_abc123def456"const response = await fetch( 'https://api.horizonplatform.ai/api/skills/quickbooks/v1.0/profit-and-loss-report', { headers: { 'x-api-key': 'hz_live_abc123def456' } });
const skill = await response.json();console.log(skill.display_name);console.log(JSON.stringify(skill.parameters_schema, null, 2));import requestsimport json
response = requests.get( 'https://api.horizonplatform.ai/api/skills/quickbooks/v1.0/profit-and-loss-report', headers={'x-api-key': 'hz_live_abc123def456'})
skill = response.json()print(skill['display_name'])print(json.dumps(skill['parameters_schema'], indent=2))Response
Section titled “Response”// 200 OK{ "id": "sk_001", "category": "quickbooks", "skill_name": "profit-and-loss-report", "version": "v1.0", "display_name": "Profit & Loss Report", "description": "Generate a Profit & Loss report from QuickBooks Online for a specified date range and accounting method.", "parameters_schema": { "type": "object", "properties": { "start_date": { "type": "string", "format": "date", "description": "Start date for the report period (YYYY-MM-DD)." }, "end_date": { "type": "string", "format": "date", "description": "End date for the report period (YYYY-MM-DD)." }, "accounting_method": { "type": "string", "enum": ["Accrual", "Cash"], "description": "The accounting method for the report." } }, "required": ["start_date", "end_date"] }, "output_schema": { "type": "object", "properties": { "report_title": { "type": "string" }, "total_income": { "type": "number" }, "total_expenses": { "type": "number" }, "net_income": { "type": "number" }, "line_items": { "type": "array", "items": { "type": "object", "properties": { "account": { "type": "string" }, "amount": { "type": "number" } } } } } }, "required_scopes": ["quickbooks"], "is_active": true, "created_at": "2026-01-15T10:00:00Z", "updated_at": "2026-03-01T08:30:00Z"}The parameters_schema field is a standard JSON Schema object that describes the input your request body must conform to when executing this skill. Use it to build dynamic forms, validate input client-side, or generate documentation automatically.
Using the Registry for Dynamic Skill Execution
Section titled “Using the Registry for Dynamic Skill Execution”A common pattern is to query the registry at runtime to build a dynamic skill execution layer. For example:
// 1. Discover available skills in a categoryconst skills = await fetch( 'https://api.horizonplatform.ai/api/skills?category=quickbooks', { headers: { 'x-api-key': apiKey } }).then(r => r.json());
// 2. Get the full schema for the skill you want to executeconst skill = await fetch( `https://api.horizonplatform.ai/api/skills/${skills[0].category}/${skills[0].version}/${skills[0].skill_name}`, { headers: { 'x-api-key': apiKey } }).then(r => r.json());
// 3. Validate input against the parameter schema (using ajv or similar)// 4. Execute the skillconst result = await fetch( `https://api.horizonplatform.ai/api/${skill.category}/${skill.version}/${skill.skill_name}`, { method: 'POST', headers: { 'x-api-key': apiKey, 'Content-Type': 'application/json', }, body: JSON.stringify(inputData), }).then(r => r.json());This approach decouples your application from hard-coded skill paths and allows it to adapt automatically as new skills are added to the registry.
Versioning Strategy
Section titled “Versioning Strategy”Horizon follows a straightforward versioning model for skills:
- Patch updates (bug fixes, minor output changes) are applied in-place to the existing version.
- Breaking changes (new required parameters, changed output structure) result in a new version (e.g.,
v1.0tov2.0). - Old versions remain active until explicitly deprecated, so existing integrations continue to work.
When a new version of a skill is published, both versions coexist in the registry. Clients can query both and migrate at their own pace.
Error Responses
Section titled “Error Responses”| Status | Error | Description |
|---|---|---|
401 | authentication_required | Missing or invalid API key. |
403 | insufficient_scope | API key lacks the required scope. |
404 | skill_not_found | No active skill matches the specified category, version, and name. |
400 | validation_error | Invalid query parameter values. |
429 | rate_limit_exceeded | API key rate limit exceeded. |