Tenon is part of Apache BifroMQ (Incubating). See the incubation disclaimer.
The running binary serves OpenAPI 3.1 at GET /openapi.json. Use it for exact request/response schemas and error details. All responses include Tenon-Version. The management surface is intended for trusted operators; see transport and access and the security policy and threat model. Package installation and Document writes control executable workloads; read access can expose configuration secrets and diagnostic data.
| Method | Path | Operation |
|---|---|---|
| GET | /documents | List saved Document ids and ETags |
| GET, PUT, DELETE | /documents/{id} | Read, save or remove a Document |
| GET | /document-schema | Read this binary's Document Schema |
| GET | /pipelines | List concise runtime status |
| GET | /pipelines/{id} | Read status, issues and plugin details |
| GET | /pipelines/{id}/diagnostics?target=... | Subscribe to live SSE diagnostics |
| GET, POST | /plugins | List Programs or install a package |
| GET, DELETE | /plugins/{programName}/{exactVersion} | Inspect or uninstall one Program |
| GET | /plugins/{programName}/{exactVersion}/config-schema | Read Config Schema |
| GET | /plugins/{programName}/{exactVersion}/payload-contract | Read FileDescriptorSet bytes |
| GET | /metrics | Collect current metrics |
There is no separate health or Document-validation endpoint. Reading /openapi.json or /plugins can check management availability without creating state. Percent-encode each resource identity as one URL path segment.
GET returns original application/jsonc bytes and a strong ETag. Preserve the complete quoted ETag. Creation requires If-None-Match: *; replacement requires If-Match with the currently read ETag. The path id must exactly match the body id. Creation returns 201; replacement returns 204 with the new ETag. Missing preconditions produce 428, stale preconditions 412, and malformed headers 400. Static invalidity produces 422 invalid_tenon_document with issues. A custom execution policy can reject a valid candidate with 403 before persistence.
DELETE of an existing Document requires the exact If-Match and returns 204 once the saved Document has been removed. An absent Document is an idempotent 204. A successful save means the original bytes are durable and admitted; application proceeds separately. After a lost response, read the Document and compare bytes/ETags before deciding whether to retry. Do not blindly overwrite concurrent edits.
The API imposes no total Document or compressed upload byte limit. Deployment admission and resource controls must fit the environment. JSONC applies to Document/configuration input, while ordinary API responses are JSON. Schemas use application/schema+json; payload descriptors use application/x-protobuf.
Pipeline states are unready, starting, updating, running and restart-backoff. Plugin-instance states are starting, running, start-failed and restart-backoff. There is no independent Flow health field.
documentEtag always describes the latest persistent Document. appliedDocumentEtag appears when a live Pipeline has applied a configuration. Different ETags mean an update is pending or the saved Document is unready while the old configuration continues to run. Check plugin status and external service connectivity separately.
An unready status includes runtimeIssues, such as missing Program, platform mismatch, invalid plugin configuration, missing interface, unbound interface or invalid Lua runtime binding. Details identify the affected Program, Instance or Flow. Restart backoff can include a sanitized lastError; when an ETag is included, it identifies the configuration that failed. Resource enforcement is reported for the applied configuration, not an unexecuted desired one.
GET /plugins returns a plugins array. Each entry and the corresponding GET /plugins/{programName}/{exactVersion} response contains programName, exactVersion, displayName, description, interface, and platforms. Display metadata comes from the installed manifest; it is validated on installation and recovery and preserved verbatim. See the field requirements. Queries do not expose the launch command or the complete manifest.
POST /plugins accepts raw gzip tar bytes with Content-Type: application/vnd.apache.tenon.plugin+tar+gzip. It does not accept multipart, Base64 or a download URL. Identity and interface come from manifest.json. A new installation returns 201, an identical normalized file set returns 204, and conflicting content for an installed identity returns 409. See package rules.
Uninstallation is blocked while persistent Documents or active execution still reference the Program. Removing a Document does not guarantee that its old processes have already exited. Query again after shutdown rather than forcing removal.
Ordinary error bodies have an error object with a stable English code and message, and endpoint-specific details where applicable. Unknown routes return 404; unsupported operations and invalid inputs follow the running OpenAPI contract. Shutdown stops admission with 503. Plugin storage failures can shut down the Runner. A Document storage failure returns 500 tenon_document_store_failed. After a failed or lost write response, read the Document to check whether the change was saved before retrying.
See observability for metric formats and diagnostic stream lifetimes.