Quickstart
From an empty install to a service that reads its database password itself. Every step is a working command; variables introduced in one step are used in the next ones.
1. Create an account
The service runs at https://env.aistastudio.ru — nothing to install or maintain. Sign up and confirm your email via the link in the message. Registration creates a personal organization — it becomes the owner of projects, members, and the plan.
The API address is the same domain with the /api/v1 prefix:
export ENVMASTER_URL=https://env.aistastudio.ru
BASE=$ENVMASTER_URL/api/v1
2. Log in and find your organization
TOKEN=$(curl -s $BASE/auth/login -H 'content-type: application/json' \
-d '{"email":"вы@example.com","password":"..."}' | jq -r .accessToken)
ORG=$(curl -s $BASE/orgs -H "authorization: Bearer $TOKEN" | jq -r .items[0].id)
A user access token lives for 15 minutes — it will expire right in the middle of this guide; just log in again.
3. Create a project and an environment
PROJECT=$(curl -s $BASE/projects -H "authorization: Bearer $TOKEN" \
-H 'content-type: application/json' \
-d "{\"orgId\":\"$ORG\",\"name\":\"Billing API\",\"slug\":\"billing-api\"}" | jq -r .id)
ENV=$(curl -s $BASE/projects/$PROJECT/environments -H "authorization: Bearer $TOKEN" \
-H 'content-type: application/json' \
-d '{"slug":"production"}' | jq -r .id)
No environments are created by default: dev, staging, production are
your choice, not a preset. The project creator automatically gets the
admin role in it, so the next steps need no extra permissions.
4. Store a secret
curl -s "$BASE/projects/$PROJECT/entries?env=production" \
-X PUT -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"key":"DB_PASSWORD","kind":"secret","visibility":"masked","value":"s3cret"}'
A secret must be masked or restricted; a variable — only plain. Key
names are uppercase letters, digits, and underscores, starting with a letter.
5. Create a service
A service is what you deploy; without it there is nothing to grant credentials to:
SERVICE=$(curl -s $BASE/projects/$PROJECT/services -H "authorization: Bearer $TOKEN" \
-H 'content-type: application/json' \
-d '{"name":"Billing worker","slug":"billing-worker"}' | jq -r .id)
6. Issue an identity to the service
An identity is the credentials of one service in one environment. Here —
universal mode with a permanent client secret:
curl -s $BASE/services/$SERVICE/identities -H "authorization: Bearer $TOKEN" \
-H 'content-type: application/json' \
-d "{\"name\":\"prod worker\",\"environmentId\":\"$ENV\",\"mode\":\"universal\",\"allowedKeys\":[\"DB_*\"]}"
The response contains clientId and clientSecret — the secret is shown
exactly once. Save both: they go into the service's environment
variables next. A lost secret is not recovered; a new identity is issued.
If issuance goes through CI and the client secret ends up in logs or an
image along the way, use the enrollment mode instead — a one-time token
the service exchanges for permanent credentials on its first start:
Services and identities.
7. Connect the service
npm i @env-master/sdk # or bun add @env-master/sdk
import { EnvMasterClient } from "@env-master/sdk";
const em = new EnvMasterClient({
baseUrl: process.env.ENVMASTER_URL!,
project: "billing-api",
environment: "production",
});
await em.loginMachine({
clientId: process.env.ENVMASTER_CLIENT_ID!,
clientSecret: process.env.ENVMASTER_CLIENT_SECRET!,
});
const password = await em.get("DB_PASSWORD");
Done. From here the value can be changed in the dashboard — the service will pick up the current one on its next start, and with rotation without a restart at all.
Migrating an existing .env
ENVMASTER_TOKEN=... envmaster import .env \
--project billing-api --env production --dry-run
The command decides on its own what looks like a secret and shows the plan before writing. Details — in the CLI.