Skip to content

The Route Management API exposes the routing engine used by Hoody’s script executor. Use these endpoints to resolve a URL path to its underlying script, discover all available routes, batch-test routing rules, and manage the OpenAPI specifications generated from your user scripts and imported SDKs.

Endpoints are grouped into three areas:

  • SDK Management — list, import, retrieve, and delete SDK bundles.
  • User OpenAPI — inspect, generate, validate, and merge OpenAPI specs derived from user scripts.
  • Route Operations — discover, resolve, and batch-test URL routes.

Retrieve the metadata for a single SDK bundle, including its source URL, file inventory, and pre/post middleware configuration.

NameInTypeRequiredDescription
idpathstringYesSDK identifier
{
"id": "sdk_01HV8Z3KQ4M5N6P7R8S9T",
"type": "sdk",
"source_url": "https://github.com/example-org/example-sdk",
"path": "/scripts/sdk/example-sdk",
"marker": "// @hoody-sdk",
"middleware": {
"pre": {
"exists": true,
"path": "/scripts/sdk/example-sdk/pre.ts",
"hash": "sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
},
"post": {
"exists": false,
"path": null,
"hash": null
}
},
"files": {
"total": 42,
"endpoints": 18,
"list": [
"/scripts/sdk/example-sdk/index.ts",
"/scripts/sdk/example-sdk/users/[id].ts"
]
}
}
const sdk = await client.exec.sdk.get({ id: "sdk_01HV8Z3KQ4M5N6P7R8S9T" });

List every SDK currently registered with the executor. Returns a flat array of SDK summaries plus a total count.

This endpoint takes no parameters.

{
"sdks": [
{
"id": "sdk_01HV8Z3KQ4M5N6P7R8S9T",
"source_url": "https://github.com/example-org/example-sdk",
"files": 42,
"middleware": {
"pre": true,
"post": false
},
"marker": "// @hoody-sdk"
},
{
"id": "sdk_02AB3CD4EF5GH6JK7LM8N",
"source_url": "https://github.com/example-org/another-sdk",
"files": 17,
"middleware": {
"pre": false,
"post": true
},
"marker": "// @hoody-sdk"
}
],
"total": 2
}
const { sdks, total } = await client.exec.sdk.list();

Import an SDK bundle from a remote source. Returns a per-file diff summary (new, updated, conflicts) plus the stored SDK metadata.

This endpoint takes no parameters.

NameTypeRequiredDefaultDescription
execIdstringYesExec identifier that owns this SDK
source_urlstringYesGit URL or archive URL to import from
source_authstringNoAuthentication string for private sources
middlewarestringNoOptional middleware bundle reference
magic_commentsstringNoMagic comment directives for import
forcebooleanNofalseOverwrite conflicting files
{
"execId": "exec_01HV8Z3KQ4M5N6P7R8S9T",
"source_url": "https://github.com/example-org/example-sdk",
"source_auth": "ghp_xxx",
"force": false
}
{
"action": "imported",
"summary": {
"new": 36,
"updated": 4,
"conflicts": 2,
"total": 42
},
"sdk": {
"id": "sdk_01HV8Z3KQ4M5N6P7R8S9T",
"source_url": "https://github.com/example-org/example-sdk",
"path": "/scripts/sdk/example-sdk",
"files": {
"endpoints": 18,
"pre": "/scripts/sdk/example-sdk/pre.ts",
"post": "",
"marker": "// @hoody-sdk"
}
}
}
await client.exec.sdk.importSDK({
execId: "exec_01HV8Z3KQ4M5N6P7R8S9T",
source_url: "https://github.com/example-org/example-sdk",
});

Remove an SDK bundle from the executor and report what was deleted (marker, file count, directory).

NameInTypeRequiredDescription
idpathstringYesSDK identifier
{
"message": "SDK deleted",
"removed": {
"marker": "// @hoody-sdk",
"files": 42,
"directory": "/scripts/sdk/example-sdk"
}
}
await client.exec.sdk.delete({ id: "sdk_01HV8Z3KQ4M5N6P7R8S9T" });

List available user scripts along with their schema metadata. Useful for discovering which scripts have OpenAPI schemas and what path parameters each one declares.

NameInTypeRequiredDefaultDescription
directoryquerystringNoscriptsScript directory to list (absolute or relative to scripts-dir)
dirquerystringNoAlias of directory. Ignored when directory is provided
subdomainquerystringNoLimit scan to scripts under this subdomain. Falls back to the Host header when omitted
execIdquerystringNoLimit scan to scripts under this execId. Falls back to the Host header when omitted
{
"success": true,
"data": {
"directory": "scripts",
"totalScripts": 12,
"withSchemas": 8,
"scripts": [
{
"path": "default/api/users/[id].ts",
"routePath": "/api/users/[id]",
"hasSchema": true,
"schemaFormat": "zod",
"pathParameters": ["id"]
},
{
"path": "default/api/posts/index.ts",
"routePath": "/api/posts",
"hasSchema": false,
"schemaFormat": null,
"pathParameters": []
}
]
}
}
const { data } = await client.exec.openapi.listScripts({
directory: "scripts",
});

Serve a single script’s schema file directly. The response body is the raw schema (Zod or JSON Schema) without any envelope.

NameInTypeRequiredDescription
filequerystringNoAbsolute or scripts-dir-relative path to the target script (e.g. default/api/users/[id].ts). Either file or path must be provided
pathquerystringNoAlias of file. Either file or path must be provided
{
"type": "object",
"properties": {
"id": { "type": "string" },
"name": { "type": "string" }
},
"required": ["id", "name"]
}
const schema = await client.exec.openapi.serveSchema({
file: "default/api/users/[id].ts",
});

Generate and serve the full OpenAPI specification for the user script directory on-the-fly. Output format is selectable via the format parameter.

NameInTypeRequiredDefaultDescription
dirquerystringNoscriptsScript directory to scan (absolute or relative to scripts-dir)
directoryquerystringNoAlias of dir. Ignored when dir is provided
formatquerystringNojsonOutput format. One of json or yaml
subdomainquerystringNoLimit scan to scripts under this subdomain. Falls back to the Host header when omitted
execIdquerystringNoLimit scan to scripts under this execId. Falls back to the Host header when omitted
{
"openapi": "3.1.0",
"info": {
"title": "User API",
"version": "1.0.0"
},
"paths": {
"/api/users/{id}": {
"get": {
"summary": "Get user by id",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": { "type": "string" }
}
]
}
}
}
}
const spec = await client.exec.openapi.serve({
dir: "scripts",
format: "json",
});

Trigger a fresh OpenAPI generation pass over the user script directory. The response contains the generated spec and metadata about the scan.

This endpoint takes no parameters.

This endpoint accepts a JSON request body. No specific body fields are documented.

{}
{
"success": true,
"data": {
"openapi": "3.1.0",
"info": { "title": "User API", "version": "1.0.0" },
"paths": {}
},
"meta": {
"pathCount": 12,
"scanDirectory": "scripts",
"generatedAt": "2025-01-15T12:00:00.000Z"
}
}
const { data, meta } = await client.exec.openapi.generate({});

Merge multiple OpenAPI specifications into a single document. Useful for combining generated user specs with third-party SDK specs.

This endpoint takes no parameters.

This endpoint accepts a JSON request body. No specific body fields are documented.

{}
{
"success": true,
"data": {
"openapi": "3.1.0",
"info": { "title": "Combined API", "version": "1.0.0" },
"paths": {
"/api/users/{id}": {},
"/api/posts": {}
}
}
}
const { data } = await client.exec.openapi.merge({});

Validate a script’s schema file. Returns a success flag, optional structured data, and a list of human-readable error messages when validation fails.

This endpoint takes no parameters.

This endpoint accepts a JSON request body. No specific body fields are documented.

{}
{
"success": true,
"data": {
"valid": true,
"warnings": []
},
"errors": []
}
const result = await client.exec.openapi.validateSchema({});

Discover every route available in the script directory. Each route is classified by Next.js-style type (static, dynamic, catchall, or optional-catchall), with extracted parameter names. Optionally include file metadata (size, modification time).

This endpoint takes no parameters.

NameTypeRequiredDefaultDescription
baseDirstringNo""Base directory to scan
includeMetadatabooleanNofalseWhen true, includes per-file size and modification time
{
"baseDir": "scripts",
"includeMetadata": true
}
{
"baseDir": "scripts",
"count": 3,
"routes": [
{
"pattern": "/api/posts",
"filePath": "scripts/default/api/posts/index.ts",
"type": "static",
"params": []
},
{
"pattern": "/api/users/[id]",
"filePath": "scripts/default/api/users/[id].ts",
"type": "dynamic",
"params": ["id"]
},
{
"pattern": "/api/docs/[...slug]",
"filePath": "scripts/default/api/docs/[...slug].ts",
"type": "catchall",
"params": ["slug"]
}
]
}
const { routes, count } = await client.exec.route.discover({
baseDir: "scripts",
includeMetadata: true,
});

Resolve a single URL path to the script file that would handle it. Supports static routes, [param], [...slug], and [[...path]]. Returns the matched script path, the extracted route parameters, the route type, and the directories that were searched.

This endpoint takes no parameters.

This endpoint requires a JSON request body. No specific body fields are documented.

{}
{
"matched": true,
"path": "/api/users/42",
"hostname": "api.example.com",
"execId": "exec_01HV8Z3KQ4M5N6P7R8S9T",
"triedDirectories": [
"scripts/api.example.com/exec_01HV8Z3KQ4M5N6P7R8S9T",
"scripts/api.example.com",
"scripts/exec_01HV8Z3KQ4M5N6P7R8S9T",
"scripts"
]
}
const result = await client.exec.route.resolve({});

Batch-test multiple URL paths against the routing system in a single request. Each path is resolved using the same priority and scoping rules as resolveRoute. The response includes per-path results plus aggregate matched / notMatched counts.

This endpoint takes no parameters.

This endpoint requires a JSON request body. No specific body fields are documented.

{}
{
"tested": 3,
"matched": 2,
"notMatched": 1,
"results": [
{
"path": "/api/posts",
"matched": true,
"scriptPath": "scripts/default/api/posts/index.ts",
"type": "static",
"params": {}
},
{
"path": "/api/users/42",
"matched": true,
"scriptPath": "scripts/default/api/users/[id].ts",
"type": "dynamic",
"params": { "id": "42" }
},
{
"path": "/api/does-not-exist",
"matched": false,
"scriptPath": null,
"type": null,
"params": {}
}
]
}
const { matched, notMatched, results } = await client.exec.route.test({});