Overview
The automation API is elchi's public REST API for scripts, pipelines and other tools. It is separate from the API the elchi UI uses: it takes only project API tokens, it is versioned, and every endpoint follows the same conventions, described on this page.
It covers two domains:
- the endpoint disable: taking an upstream endpoint (an IP or a hostname) out of rotation everywhere it is used in a project, and putting it back;
- the cluster switch: pointing an EDS cluster at another endpoints resource, for a blue/green release.
Base URL
https://<your elchi address>/api/public/v1
The major version is in the path. The front-door Envoy of an elchi installation routes /api/public/ to the controller.
The API is described by an OpenAPI 3.0 document, served without a token:
| Path | Content |
|---|---|
GET /api/public/v1/openapi.json | The document as JSON |
GET /api/public/v1/openapi.yaml | The document as YAML |
Point a generator (for example openapi-generator) or a tool such as Postman at it. The elchi UI also renders the same document as an interactive reference under Administration → API Reference (/api-docs). It includes ready-to-copy curl commands with your project filled in.
A first call
- Create a token in Settings → Tokens (see API tokens) and keep it in your pipeline's secrets.
- Check it:
export ELCHI_TOKEN=elchi_pat_…
curl -sS -H "Authorization: Bearer $ELCHI_TOKEN" https://elchi.example.com/api/public/v1/token
The answer names the token's project and scopes. Every other path names the project: /api/public/v1/projects/{project}/….
The values a call needs
| Value | Where to find it |
|---|---|
| Project ID | project in GET /token. In the UI: Settings → Tokens shows it (and the dialog of a new token), and the API Reference fills it into its examples. |
| Envoy version | GET /projects/{project}/versions: the versions this control plane serves and the ones the project's listeners, clusters or endpoints resources are on, newest first. The clusters API takes one as version. |
| Cluster and endpoints resource names | GET /projects/{project}/clusters?version=… and, for one cluster, its candidates. |
| Endpoint address | GET /projects/{project}/endpoints lists every address the project uses. |
| Operation ID | The id (and the Location header) of a change's answer; GET /projects/{project}/operations lists them. |
curl -sS -H "Authorization: Bearer $ELCHI_TOKEN" https://elchi.example.com/api/public/v1/projects/$P/versions
{"items": [
{"version": "v1.40.2", "status": "served", "listeners": 12, "clusters": 30, "endpoints": 8},
{"version": "v1.39.4", "status": "served", "listeners": 0, "clusters": 0, "endpoints": 0}
]}
status is served when a control plane serves the version now. not_configured means this control plane no longer serves it, so its resources reach no proxy. no_control_plane means it is configured, but no control plane for it is running. unknown means the control planes could not be read.
Conventions
These rules hold for every endpoint, now and in the future.
Errors
Every error is application/problem+json (RFC 9457). It carries a stable code from a closed list and the request_id. For an invalid request whose field can be named, it also has errors, each with a JSON Pointer to the field at fault. Switch on code, never on the text. The codes and what to do about each are on Errors and codes.
Request ids
Send X-Request-Id (1–128 characters of A-Za-z0-9._:-) to tie a call to your logs. It is echoed on every response and recorded in the audit log. Without it, elchi makes one.
Retries
GETis always safe to send again.- Every
POSTtakes anIdempotency-Key: 1–255 visible ASCII characters, such as a UUID. The same key with the same request returns the first answer for 24 hours, markedIdempotent-Replayed: true. The same key with a different request (another body orIf-Match) is refused withidempotency_key_reused. A5xxanswer is not kept: the same key runs the request again. - Retry
429and503afterRetry-After, and500with backoff. - Never retry another
4xxunchanged.
Concurrency
A resource that can change under you has an ETag. Send it as If-Match to change the resource only if it did not change since you read it; otherwise the answer is 412 precondition_failed. Send it as If-None-Match on a GET to get 304 Not Modified when nothing changed.
Long-running operations
An action that pushes configuration to the proxies answers 202 Accepted with an operation and a Location header.
- Follow it with
GET …/projects/{project}/operations/{id}. Add?wait=Nto hold the request until the operation ends, up to 60 seconds. - Or ask the action itself to wait:
Prefer: wait=N(up to 60). The answer then carriesPreference-Applied. When the operation ends within that time, the answer is200with the finished operation; otherwise it is the usual202.
An operation ends succeeded or failed.
succeededmeans the new configuration is set on every control plane that serves the affected proxies. It does not mean every proxy has acknowledged it.failedlists the proxies the push did not reach infailed_nodes.
The project's operations are listed newest first and kept for 30 days.
Formats
- Times are RFC 3339 in UTC, with milliseconds.
- Fields are
snake_case. - An enum marked
x-extensible-enummay gain values; treat an unknown value as opaque. - Lists page with
limitand an opaquenext_cursor. Passcursorto read the next page, with the same filters as the first one. - Unknown query parameters and unknown body fields are refused (
400 invalid_request). - A request body is at most 1 MiB of
application/json.
Rate limits
Each token may send 300 requests a minute, of which 30 writes.
- Every response to an authenticated request carries
RateLimit-Limit,RateLimit-RemainingandRateLimit-Reset. On a write they describe the write budget. - Over the limit, the answer is
429 rate_limitedwithRetry-After. - The budget refills continuously (a token bucket). It is counted by each controller replica: behind N replicas a token may send up to N times as many.
- Failed authentication is limited separately: 60 a minute per client address.
Versioning
Within v1, changes only add things: new operations, optional fields, and new values of extensible enums. A change that would break a client becomes v2, and v1 then stays available for at least 12 months. A deprecated operation sends Deprecation, Sunset and a Link to its replacement.