API reference

Generated from openapi.json 0.12.0-draft (draft)

Public API of the Hetscale control plane: the groups and their projects, the node reports, the release pointer, the inventory API, the deploy lock, the in-place deploy report, the rollout and the Prometheus endpoint, plus the signed deliveries Hetscale sends to the customer's endpoints: the webhook adapter's deployment events and, on Pro, the integrations' timeline events, alerts and tests. Operations marked implemented are served under /v1 on api.hetscale.com; the others are planned and may still change. Eight operations are stable and marked x-hetscale-stability: stable: the ones a deploy pipeline calls to hold and release a group's deploy lock, create a release, list a group's nodes, report an in-place deploy, start a rollout, and report that the deploy to a new node succeeded or failed. Within /v1, what a pipeline sends them and reads from their answers is not removed, renamed or narrowed: the method, path and ability of each, the request fields and their bounds, the success statuses, the answer fields a pipeline uses (the lock's end; the release's id, version, ref and build id and the group's generation; each node's id, class, phase, IPv4 address, private address and release; the rollout's id and its count of older servers; the reported node's phase), the node phases, Retry-After, and the error body and its codes. Everything else in this document is a draft and may still change before it leaves draft.

Base URL: https://api.hetscale.com/v1. Every request and response body is JSON. The specification is the source of these pages; nothing here is written by hand. The file itself is openapi.json (OpenAPI 3.1.0, version 0.12.0-draft). It is a draft, except the operations marked stable, so the rest may still change. Import it into an API client or a code generator.

Authentication

Authorization: Bearer <token> on every request. An organisation's API token from the panel's API tokens page, sent as Authorization: Bearer <id>|<secret>. A token acts for the member who created it and stops working when that member leaves the organisation. It may do only what its abilities allow: nodes:report, releases:write, groups:lock, nodes:read, rollouts:write, metrics:read, groups:read and groups:write. An ability counts only while the member's role holds it: reads for every member, the node reports, releases, the deploy lock and the rollout for an operator, a group's changes for an admin; an ability above the role is answered 403 forbidden.Tokens are never sent in a URL. A token is shown once, when you make it on the API tokens page, and expires after 30, 90 or 365 days, or never; 90 is the default. Each organisation may send 60 requests a minute. A request may carry an Idempotency-Key header: a retry by the same token with the same key and the same request within 24 hours gets the first answer again.

Endpoints

get /groupsList the organisation's groups
post /groupsStart observing a load balancer
get /groups/{groupId}Read a group
patch /groups/{groupId}Change a group's settings
delete /groups/{groupId}Archive a group
post /groups/{groupId}/restoreBring a group back from the Archive
get /groups/{groupId}/nodesList the current nodes of a group · stable
post /groups/{groupId}/lockHold a deploy lock on a group · stable
delete /groups/{groupId}/lockRelease a group's deploy lock · stable
post /groups/{groupId}/rolloutReplace a group's older servers · stable
delete /groups/{groupId}/rolloutStop replacing a group's older servers
get /projectsList the organisation's Hetzner projects
post /nodes/{nodeId}/readyReport that a node has been deployed · stable
post /nodes/{nodeId}/failedReport that the deploy to a node failed · stable
post /nodes/{nodeId}/deployedReport an in-place deploy on a node · stable
post /groups/{groupId}/releasesCreate a release and move the group's current pointer to it · stable
get /metricsRead every group's gauges in the Prometheus text format
webhook timelineA timeline event of one of the organisation's groups
webhook alertAn alert of the organisation
webhook pingThe Integrations page's test
webhook node.createdA new node is booted and reachable
webhook node.terminatingA node is leaving the group
webhook group.release_changedThe group's current release changed

Groups · Projects · Nodes · Releases · Metrics · Webhooks

Errors

Errors return the Error schema:400 when an Idempotency-Key is malformed, 401 when the token is missing or invalid, 403 when it lacks the ability the operation needs or when the role of the member who made the token no longer holds that ability (Team's roles),404 when the group or node is not in your organisation, 409 when a report changes nothing, a request of the same token with the same key is still being handled, the group is not Live or paused for a release or the deploy lock (not Live for a rollout), a rollout already runs or has nothing to replace, or an in-place report names a server that is not a serving managed server of a webhook group, 422 when the body fails validation, names a release the group does not have, or reuses an Idempotency-Key with a different request or from another token, 429 when the rate limit is exceeded, and502 or 503 when Hetzner fails while a release is read back from your project; a 503 may be retried.

Schemas

PolicyRule

FieldTypeDescription
metric*cpu_percent · lb_requests_per_second · lb_open_connectionsWhat the rule reads: the servers' CPU in percent, or the load balancer's requests per second or open connections per server.
threshold*numberThe value the metric must stay above (scale-out) or below (scale-in) for the whole window.
window_seconds*integerHow long the metric must hold, in seconds.

* required

GroupSettings

What a member changes on a group: the panel's Settings page, the SSH keys of new servers and the decision mode. It is the body `PATCH /groups/{groupId}` takes, whole or in part, and its digest is the group's `ETag`. The panel's Export settings downloads this block alone. A field it does not list, at any depth, is refused with `validation_failed` under the field's path, and so is a whole group document sent back instead of this block. `minimum` and `maximum` give a number's range, `x-hetscale-initial` the value a new group starts with.

FieldTypeDescription
minintegerThe fewest servers the group keeps. Bounded by the group: at least the servers that cannot leave, at most max.
maxintegerThe most servers the group runs: one under the load balancer's target limit once its targets that are not servers of the group are taken off, so a replacement has a target beside the server it replaces, and within the room the private network new servers join has left, one place kept free for a replacement there too.
policyobjectThe scaling policy. A group keeps the values of the preset it took until a member takes the preset's values of today. A named preset sets every other field, which is accepted only when it matches the values the group keeps or the preset's values today; a body that matches only today's takes all of today's values, not just the fields it sends; naming the group's own preset alone keeps its values; target writes them from its target (one metric and the value to hold, on Pro and Team; plan_required otherwise), from the values the group keeps or from today's Balanced, and they too are accepted only when they match; custom takes each field, and a field left out keeps its value. Scale-in must stay stricter than scale-out.
drain_window_secondsintegerHow long a leaving server keeps its connections after it leaves the load balancer: 10 to 300 seconds.Default 60Range 10–300
readiness_deadline_secondsintegerHow long a new server may take to pass the load balancer's health check: 300 to 3,600 seconds.Default 900Range 300–3,600
keep_failed_nodes_secondsintegerHow long a failed server is kept for a look before it is deleted: 0 to 7,200 seconds.Default 0Range 0–7,200
euro_ceilinginteger | nullThe monthly euros the group's added servers may cost at list prices, 1 to 1,000,000; null for none.Default nullRange 1–1,000,000
release_age_warning_daysinteger | nullThe age in days, 1 to 365, at which the current release warns; null for never.Default 30Range 1–365
fallbackobjectWhat happens when the group's type is out of stock.
hold_scale_in_while_sold_outbooleanKeep the servers a scale-in would remove while the central stock poll, read within the last 3 minutes, flags every type and location the group's next create would try as out of stock; at most 24 hours per stock-out. Off by default.Default false
placementspread · none · nullspread puts new servers on different physical hosts; null keeps it.
ssh_key_idsarray of integerThe Hetzner ids of the public keys of the group's project that new servers get, among those the latest read of the project found.
decision_modeautomatic · proposeautomatic acts on the policy's decisions, propose waits for a member to approve each one on the panel.

GroupSummary

FieldTypeDescription
id*stringGroup identifier, a ULID prefixed with grp_.
name*string
state*observe · rehearsing · live · paused
project*object | null
min*integer
desired*integer
max*integer
archived_at*string | null (date-time)When the group went to the Archive, or null.

* required

GroupDocument

A group as one document, also its JSON export: the panel's Export JSON downloads the same. A webhook secret, the template's user data and any token never appear.

FieldTypeDescription

Project

FieldTypeDescription
id*stringProject identifier, a ULID prefixed with prj_.
name*string
status*active · revoked · deletedWhether Hetscale can still reach the project with its token.
token_level*read · read_write
created_at*string (date-time)

* required

CreateGroup

FieldTypeDescription
project*stringThe project's prj_ id, from GET /projects.
load_balancer_id*integerThe Hetzner id of the load balancer to observe.
seed_server_id*integerThe Hetzner id of one of your servers behind it, the seed new servers are made from.
name*string
server_prefixstring | nullThe middle of the group's server names; by default one the name suggests.
answers*objectThe panel's case questions, assessed against the project's latest read.

* required

DeliveryOrganization

The organisation an integration's delivery comes from.

FieldTypeDescription
id*stringOrganisation identifier, a ULID prefixed with org_.
name*string

* required

DeliveryGroup

The group a delivery is about.

FieldTypeDescription
id*stringGroup identifier, a ULID prefixed with grp_.
name*string

* required

DeliveryNode

The server a delivery is about.

FieldTypeDescription
id*stringNode identifier, a ULID prefixed with node_.
name*string | nullThe server's name in Hetzner Cloud.
server_id*integer | nullId of the server in the customer's Hetzner Cloud project.

* required

Group

FieldTypeDescription
id*stringGroup identifier, a ULID prefixed with grp_.
name*stringName of the group as shown in the panel.
generation*integerCounter incremented on every template or release change; a scaling decision made against an older generation is discarded. In node.created, the generation the node was created for.

* required

Node

FieldTypeDescription
id*stringNode identifier, a ULID prefixed with node_.
server_id*integer | nullId of the server in the customer's Hetzner Cloud project, or null before it is created.
name*string | nullServer name in Hetzner Cloud: hetscale-<group prefix>-<number> for a server Hetscale created (for example hetscale-web-7), hetscale-<group prefix>-0 for a promoted seed, the customer's own name for an adopted server.
class*adopted · managedadopted is the seed server the customer already ran, which is never scaled in or replaced; managed nodes were created by Hetscale and have the full lifecycle.
phase*REQUESTED · PROVISIONING · BOOTING · DEPLOYING · HEALTH_CHECKING · ACTIVE · DRAINING · TERMINATING · TERMINATED · PROVISION_FAILED · DEPLOY_FAILED · HEALTH_FAILED · DRAIN_TIMEOUT · TERMINATION_FAILEDCurrent phase in the node lifecycle; only ACTIVE nodes receive traffic.
ipv4*string | nullPublic IPv4 address, or null when the server has none.
ipv6*string | nullPublic IPv6 address, or null when the server has none.
private_ip*string | nullAddress in the group's private network, or null when the server is not attached to one.
location*string | nullHetzner Cloud location the server runs in, such as nbg1.
server_type*string | nullHetzner Cloud server type the server was created with, such as cx23.
release*objectThe release the node runs, or null for a server that names none, such as a promoted seed.
build_id*string | nullThe build id of the release the node runs, or null when that release has none.
phase_entered_at*string (date-time)When the node entered its current phase.
older*booleanTrue when the node runs another release than the group's current one, none, a template version that differs in what changes a running server, or no placement group while the group spreads its servers across hosts. A rollout replaces it, except while the load balancer no longer lists it as a target.

* required

Release

FieldTypeDescription
id*stringRelease identifier, a ULID prefixed with rel_.
versionintegerThe release's number within its group, v1 the first.
ref*stringThe artefact the release boots from: a Hetzner snapshot id, an image digest or a Coolify deployment reference.
build_id*string | nullThe customer's own build identifier for the release, or null when none was given.
source*snapshot · image · coolify · apiHow the release was created: a snapshot of the seed, an image digest, a Coolify deployment or the releases endpoint.
created_at*string (date-time)When the release was recorded.

* required

Error

FieldTypeDescription
message*stringHuman-readable description of the error.
code*stringStable machine-readable reason: unauthenticated, forbidden, not_found, method_not_allowed, validation_failed, rate_limited, idempotency_key_invalid, idempotency_key_reused, idempotency_key_in_flight, provider_unavailable, key_service_unavailable, secrets_unavailable, provider_error, plan_required, precondition_failed, or the reason an operation changed nothing, such as stale_generation or image_not_found.
errorsobjectValidation messages keyed by field name; present on 422 responses only.
nodeNodeState

* required

NodeReport

FieldTypeDescription
release*stringThe release the pipeline deployed, as node.created sent it.
generation*integerThe group generation the node was created for, as node.created sent it.Range ≥ 1

* required

NodeState

FieldTypeDescription
id*stringNode identifier, a ULID prefixed with node_.
phase*stringCurrent phase in the node lifecycle, as in Node.
generation*integerThe group generation the node was created for.
release*string | nullIdentifier of the release the node boots from, prefixed with rel_.
ready_reported_at*string | null (date-time)When the first ready report was taken, or null.
failed_reported_at*string | null (date-time)When the first failure report was taken, or null.

* required

See what Hetscale would have done with your real data — connect read-only, get your report in minutes.

Connect read-only