{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "endpoint-descriptor.schema.json", "title": "Custom Endpoint Descriptor", "description": "Defines a custom HTTP endpoint that executes server-side JavaScript code.", "markdownDescription": "AI guidance: use custom endpoints for model-owned actions and lightweight APIs. `name` must be unique. `route` should start with `/api/` and must not conflict with another route/method. Use `{id}` style path parameters when needed. Scripts can access request data through the endpoint context and return HTTP results with helpers such as `context.ok(value)`, `context.created(value)`, and `context.noContent()` where available. Require authentication by default and add `requiredPermissions` for protected operations.", "type": "object", "properties": { "$schema": { "type": "string", "description": "Optional schema reference used when this descriptor is stored as a model descriptor file." }, "name": { "type": "string", "description": "Unique endpoint identifier used by designer/model health. Prefer PascalCase or kebab-case, for example 'SearchCustomers'.", "minLength": 1 }, "route": { "type": "string", "description": "URL route pattern. Must start with '/' and should use an application-specific prefix such as '/api/low-code/events/{id}'. Route parameters use ASP.NET style braces, for example '{id}'.", "minLength": 1, "pattern": "^/" }, "method": { "type": "string", "description": "HTTP method. GET should be read-only; POST/PUT/PATCH/DELETE may mutate state.", "enum": ["GET", "POST", "PUT", "DELETE", "PATCH"], "default": "GET" }, "javascript": { "type": "string", "description": "JavaScript code to execute. Use context request/response helpers and services exposed by the host, such as db, currentUser/currentTenant, authorization, emailSender, config, http, event bus, background jobs, and logging helpers.", "minLength": 1 }, "requireAuthentication": { "type": "boolean", "description": "Whether authentication is required. Keep true unless this endpoint is intentionally public.", "default": true }, "requiredPermissions": { "type": "array", "description": "Permission names required to access the endpoint. Checked only when authentication is required. Values should reference custom permissions or known static permissions.", "items": { "type": "string" } }, "description": { "type": "string", "description": "Optional human-readable description for designer documentation and model health context." } }, "required": ["name", "route", "javascript"], "additionalProperties": false, "examples": [ { "name": "SearchCustomers", "route": "/api/low-code/customers/search", "method": "GET", "requireAuthentication": true, "requiredPermissions": ["Acme.Customers.View"], "javascript": "var q = context.request.query.q || ''; var table = await db.query('Acme.Crm.Customer'); var rows = await table.where(c => c.Name.toLowerCase().includes(q.toLowerCase())).take(10).toList(); return context.ok(rows);" } ] }