REST API & tokens
There’s no hidden side to the web UI: everything it does goes through the REST API under
/api/v1/. That means you can do all of it from a script, too. Scripts, CI jobs, the
command line and MCP all use it with API
tokens.
Creating a token
Section titled “Creating a token”Go to Settings → API tokens & MCP, type a name under New token, pick its scope, limit it to
projects if you want, and click Create token. You see the value (it starts with stq_)
exactly once, so copy it right away - Envoryx only keeps a hash and can’t show it again. If a
token leaks, revoke it; that takes effect immediately.
You send it as a bearer token. Requests like that need neither a session cookie nor the CSRF headers a browser sends:
curl -H "Authorization: Bearer stq_…" https://envoryx.test/api/v1/projectscurl -H "Authorization: Bearer stq_…" -X POST https://envoryx.test/api/v1/projects/<id>/restartToken scopes
Section titled “Token scopes”A token doesn’t have to be able to do everything, and usually it shouldn’t. There are three levels, and each one includes the ones below it:
| Scope | Allows |
|---|---|
read |
Looking: project list and details, status, logs, statistics, backup list, runtimes. No secrets (not even the values of secret variables), no changes. |
operate |
Working with existing projects: start/stop/restart, image rollback, actions, creating backups and databases, git, domains, addons, SSH/SFTP, terminal, database browser. The default for new tokens. |
admin |
Everything an admin may do: creating and deleting projects, settings, TLS, notifications, instance backups, restores, dropping databases. |
On top of that you can limit a token to particular projects. It then only sees those, every
other project answers 403, instance-wide endpoints are closed, and it can’t create projects -
whatever its scope. People get the same levels as roles. That’s the right choice for a CI job that should deploy one project and
nothing else.
When a token isn’t allowed to do something, the answer says why
(this token has read scope, the operation needs operate). GET /api/v1/auth/me shows the
name, scope and projects of the token you’re calling with. A few things no token can do: change
the password, create or revoke tokens, manage users, and show or replace the
secret key. For those you need a browser session,
and for the last two an admin’s.
A few endpoints
Section titled “A few endpoints”Not the full list, but the ones you’ll reach for first:
| Endpoint | Purpose |
|---|---|
GET /api/v1/projects |
all projects |
POST /api/v1/projects |
create a project |
PATCH /api/v1/projects/{id} |
change runtimes and services, e.g. {"ruby": {"enabled": true, "version": "3.4", "server": true}} |
POST /api/v1/projects/{id}/start · /stop · /restart |
lifecycle |
GET /api/v1/runtimes |
versions, templates and presets Envoryx offers |
GET /api/v1/projects/{id}/tests |
test suites and recent runs |
GET/POST/DELETE /api/v1/projects/{id}/share |
a public share |
PUT /api/v1/projects/{id}/proxy-rules |
the project’s proxy rules |
GET /api/v1/audit · /audit/export |
the audit log |
GET /api/v1/system/diagnostics |
the set-up check (admin) |
GET /api/v1/health |
health, without authentication |
A few things about PATCH on services save surprises. Whatever you leave out stays as it is, so
{"memcached": {"exposePort": false}} only unpublishes the port and leaves the service in place.
{"redis": {"enabled": false}} removes Redis but keeps its data; add "removeData": true to
delete it. The same goes for RabbitMQ, Meilisearch, Typesense and OpenSearch.
GET /api/v1/projects/{id}/extras lists kept data under keptData, and
DELETE /api/v1/projects/{id}/extras/{kind}/data deletes it. Mailpit and Meilisearch always
publish their port, so "exposePort": false gets a 422 for them. A new bucket is private unless
you send "publicRead": true with storage.
Runtimes work the same way. {"go": {"enabled": true, "version": "1.27"}} changes the version and
keeps the server, its mode, package and port; leave out version and the version stays too. That
holds for every runtime, Node’s devServer included. Picking a new preset is the one exception:
it drops the stored port (and Python’s application) unless you send them along. You can also send
back a runtime object exactly as GET returned it: the read-only hostPort and debugHostPort in
it are accepted and ignored. For the database type, postgres and postgresql both mean
PostgreSQL, as in envoryx.yml.
Projects in the API carry their full url, proxy port included. Service credentials (object
storage keys, the RabbitMQ password, the Meilisearch and Typesense keys, an external Redis
password) are not part of the project responses, just like database passwords. The generated ones
come from the credentials endpoints such as GET /api/v1/projects/{id}/storage/credentials, which need
operate.
Actions, terminals and test runs stream their output over WebSockets (…/tests/{suite}/ws and
similar). That’s a bit fiddly from a shell script, which is why the CLI
wraps them for you.
Every change made through the API is written to the audit log as
user (token: name), so you can always tell afterwards which script did what.