Authentication
Every request carries an API key in an Authorization header. There is one mechanism, it is the same on every endpoint, and there is nothing to negotiate — no OAuth dance, no request signing.
The header
Send your key as a bearer token. Secrets start with esy_sk_.
curl https://api.esy.com/v1/runs \
-H "Authorization: Bearer $ESY_API_KEY"Miss it, or send a revoked key, and you get a 401:
HTTP 401
{ "detail": "Missing authentication token" }Creating a key
Keys are created in os.esy.com under Settings → API keys, or through POST /v1/api-keys from a signed-in session.
What a key can do
This is the part people get wrong. An API key acts as the user who created it. It is a credential, not a reduced-privilege role: there is no scope system that lets you mint a read-only key today. If the creating account can delete a project, so can a key it created.
The one restriction available is workspace binding. A key bound to a workspace can only touch that workspace, and a request naming any other is rejected with 403. Bind every key you create — it is the difference between a leaked key being a problem and being a catastrophe.
| Property | Behaviour |
|---|---|
| Identity | The key acts as its creating user, with that user’s permissions. |
| Workspace binding | Optional but recommended. Hard-restricts the key to one workspace. |
| Expiry | Keys do not expire on their own. Revoke them explicitly. |
| Storage | Only a SHA-256 hash is kept. The plaintext is never recoverable. |
| Rate limits | Not currently enforced per key. Do not rely on the API to throttle you. |
Checking which key you have
GET /v1/users/me tells you who a key authenticates as and which workspaces it can reach. It is the fastest way to confirm a key works and to find the workspaceId you will pass when creating runs.
curl -s https://api.esy.com/v1/users/me \
-H "Authorization: Bearer $ESY_API_KEY"{
"id": "6c24a056-…",
"email": "[email protected]",
"name": "Your Name",
"role": "admin",
"isActive": true,
"workspaceMemberships": [
{
"workspaceId": "9a1b6d4c-…",
"workspaceSlug": "your-org",
"workspaceName": "Your Org",
"workspaceKind": "organization",
"role": "owner"
}
]
}Sessions, for browsers
The dashboard authenticates with a cookie session rather than a key — POST /v1/auth/login sets an esy_session cookie and returns an access token. You almost certainly do not want this: it exists for first-party browser clients, and cross-origin cookie mutations are rejected with 403 on purpose. For server-to-server work, use a key.
Keeping a key safe
- Keep it in an environment variable or a secret manager. Never in source control, never in a client bundle, never in a URL — query strings end up in logs and browser history.
- Bind it to one workspace at creation, and create separate keys per deployment so you can revoke one without taking down everything.
- Never put a key in frontend code. A key that reaches a browser is public. Proxy Esy calls through your own backend.
- Revoke on suspicion, not on proof:
DELETE /v1/api-keys/{key_id}takes effect immediately.
createdVia, apiKeyId and apiKeyName, so you can tell exactly which credential did what.- One mechanism:
Authorization: Bearer esy_sk_…on every request. - A key acts as the user who created it. Workspace binding is the only way to narrow it.
- The secret is displayed once and stored only as a hash. Revoke and recreate rather than recover.
