API
Authentication
Every endpoint except the health check requires a bearer token. Tokens are issued per user, carry a set of scopes, and can be revoked at any time without affecting the others.
Personal access tokens
A personal access token is the credential you use for scripts, CI jobs, the CLI and both SDKs. Create one in the console under Settings → Access tokens.
The token value is shown once, at creation. There is no way to read it back afterwards — if you lose it, revoke it and issue a new one.
| Property | Detail |
|---|---|
| Prefix | hf_ followed by 64 hexadecimal characters |
| Lifetime | No expiry is selected by the current token-creation endpoint; revoke it manually when it is no longer needed. |
| Ownership | Bound to the user who created it, and revoked automatically when that user is removed. |
| Visibility | Shown once. Only a fingerprint is stored afterwards. |
Machine credentials
Developer sub-accounts add durable service principals that remain separate from the human who created them. Hubfly space stores only SHA-256 hashes and safe prefixes; the plaintext value is returned once.
| Kind | Prefix | Scope | Tenant selection |
|---|---|---|---|
| Sub-account key | hfsk_ | One fixed tenant | Inferred from the credential; a conflicting header is rejected. |
| Platform key | hfpk_ | One personal or organization parent | Send X-HubFly-Subaccount: sub_… on tenant resource calls. |
Machine principals cannot call personal profile, session, OAuth, personal-token creation, organization invitation, or payment-method endpoints. Endpoint access is default-denied and must explicitly support the credential kind. See the sub-account API guide.
Sending the token
Put the token in the Authorization header as a bearer credential. It goes on every request — the API keeps no session state between calls.
Authorization: Bearer hf_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdefcurl https://api.hubfly.space/api/v1/projects \
-H "Authorization: Bearer $HUBFLY_TOKEN"Both SDKs and the CLI read HUBFLY_TOKEN from the environment, so exporting it once is usually all the configuration you need:
export HUBFLY_TOKEN="hf_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"Session login
POST /api/v1/auth/login exchanges an email and password for a session token. It exists for interactive clients — the console and hubfly login — and is the wrong tool for automation: session tokens are short-lived, and the flow breaks the moment the account turns on multi-factor authentication.
curl -X POST https://api.hubfly.space/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "password": "…"}'Use a personal access token for anything unattended
Scopes
A token carries the scopes you grant it at creation and nothing more. A request that needs a scope the token lacks is rejected with 403, even when the underlying user would be allowed to make it.
| Scope | Grants |
|---|---|
project:read | Read project information and project-scoped resources. |
project:edit | Update project configuration. |
project:delete | Delete a project where the user has that authority. |
container:create | Create containers in an accessible project. |
container:update | Update container configuration. |
container:delete | Delete containers. |
container:control | Perform container lifecycle actions. |
container:logs | Read container logs. |
container:terminal | Open or use a container terminal. |
volume:manage | Create, inspect and remove project volumes. |
network:manage | Manage project networking and access settings. |
billing:view | Read billing information where the account permits it. |
billing:manage | Manage billing where the account permits it. |
team:manage | Manage project team access where the account permits it. |
subaccounts:read | List and inspect sub-accounts owned by the platform key's parent. |
subaccounts:manage | Create, update, suspend, and resume sub-accounts. |
subaccounts:fund | Transfer eligible paid parent balance into tenant wallets. |
subaccounts:keys:manage | Create, list, rotate, and revoke tenant machine credentials. |
subaccounts:operate | Target supported tenant resource operations. |
Grant the narrowest set that does the job. Token scopes can only reduce the issuing user's access; they never grant access the user does not already have. You can also pin a token to specific projects with projectIds (at most 50). The current create request acceptsname, scopes and projectIds; billing and team permissions are reserved for owner-level access and cannot be requested as token scopes.
Storing tokens
- Keep tokens in a secret store or your CI provider's encrypted variables.
- Never commit one. If a token reaches a repository, revoke it — rewriting history does not un-leak it.
- Do not ship a token to a browser. Anything in front-end JavaScript is readable by anyone who opens devtools.
- Give each system its own token. Shared tokens make it impossible to revoke one consumer without breaking the rest.
Rotating and revoking
Rotate without downtime by overlapping: create the replacement, roll it out everywhere, confirm traffic has moved, then revoke the old one. Because tokens are independent, the two can be live at the same time.
Revoke immediately — not on the next rotation cycle — when:
- a token has appeared anywhere it should not have, including logs or a screenshot;
- someone with access to it has left the team;
- a machine that held it has been decommissioned or compromised.
Authentication failures
| Status | Code | Cause |
|---|---|---|
401 | missing_token | No Authorization header was sent. |
401 | invalid_token | The header is malformed, or the token does not exist. |
401 | expired_token | The token passed its expiry date. |
401 | revoked_token | The token was revoked, or its owner was removed from the account. |
403 | insufficient_scope | Valid token, but it lacks the scope this endpoint needs. |
A 403 is a scope problem, not a credentials problem — reissuing the same token will not fix it. Check which scope the endpoint requires, then create a token that has it.