Update an instance pool's size, tags or launch template
Change desired_count (bounded by the pool’s min_count/max_count), the pool’s own tags, and/or the launch template. The reconciler scales the live instance set to match a new desired_count. min_count and max_count are fixed at create.
tags relabels the POOL and nothing else: it takes effect immediately,
no instance is touched, and the new set is what a later IAM condition
reads as basalt:ResourceTag/<key>. It replaces the whole set — an empty
object clears it, an omitted field leaves it alone.
A new template replaces the stored one wholesale and changes what the
pool launches NEXT; the instances already running keep what they booted
with, because a live VM cannot change flavor, tier, subnet or tags in
place. So a template.tags edit leaves the pool holding members with two
different tag sets until it is rolled. The pool reports
stale_instance_count — how many members are on the old template — and
POST /v1/instance-pools//refresh rolls them.
Authorizations
BASALTIC-HMAC-SHA256 request signing for service-account (access-key) auth.
An AWS-SigV4-style scheme: an HMAC-SHA256 over a canonical request, keyed by a
signing key derived from your secret access key. The basaltic CLI does this
for you; the steps below are for a non-CLI client.
Headers you send
Authorization(this scheme) — format below.X-Date: request time in UTC, compact ISO-8601 basic:YYYYMMDDTHHMMSSZ(e.g.20240115T103000Z). Must be within 5 minutes of server time.X-Nonce: random per-request value (e.g. 16+ bytes of hex). Required — it is what makes each signature unique so the server can reject replays.X-Datealone is not enough (one-second resolution;UNSIGNED-PAYLOADnever enters the canonical request).X-Content-Sha256(optional): lowercase-hex SHA-256 of the request body, to bind the exact bytes to the signature — the server re-hashes and rejects a mismatch. Omit it, and put the literalUNSIGNED-PAYLOADin the body-hash slot, for an empty body or a streaming upload that shouldn't be buffered.
Authorization header format
<date>:YYYYMMDD(the day part of X-Date).<region>: target region code (e.g.sa-saopaulo-1), orglobalfor the region-agnostic (IAM) endpoints.<service>:basaltic.SignedHeaders: the covered header names, lowercased and sorted, joined by;— at minimumhost;x-date;x-nonce(all three required).Signature: lowercase hex from step 4.- Note the
,(comma + space) between the three Authorization parameters.
Step 1 — canonical request
Join these six lines with \n (LF):
canonical-path: the URL-escaped request path (e.g./v1/compute/instances).canonical-query: each query key and value URL-encoded, sorted by key then value, joined by&; empty string when there is no query.canonical-headers: for each signed header,name:value(name lowercased, value trimmed), sorted by name, each followed by a trailing\n.signed-headers: the same names, lowercased, sorted, joined by;.body-hash: lowercase-hex SHA-256 of the body, or the literalUNSIGNED-PAYLOAD.
Step 2 — string to sign
Join with \n:
The second line is the credential date at midnight — NOT the X-Date value — and the third is the credential scope without the access-key id.
Step 3 — derive the signing key (HMAC chain over your secret)
Step 4 — signature
Example (POST with a JSON body)
Request validity
- Valid for 5 minutes from the X-Date timestamp.
- The signature must cover at least
host,x-date, andx-nonce. - Mutating requests (POST/PUT/PATCH/DELETE) that present a signed nonce are
anti-replay guarded for the drift window; omitting
X-Nonceis rejected.
Rate limits
There is no global request budget: a limit applies only where an operation
documents a 429 response, and each such endpoint counts its own fixed
window. Everything else is bounded by quota, not by request rate.
Per-endpoint request limits
A few endpoints are limited in front of the handler, counted per caller —
the authenticated principal when the request carries credentials, the
client IP otherwise. On this API surface that is the public region
catalogue, GET /v1/regions: it guards no secret, and the budget is there
because the catalogue is unauthenticated and database-backed.
An operation that is limited says so by documenting a 429. These
responses — 429 and 2xx — carry the budget, so a client can pace
itself instead of discovering the ceiling by hitting it:
X-RateLimit-Limit— requests allowed per window on this endpoint. Authoritative: read it rather than hard-coding a number.X-RateLimit-Remaining— requests left in the window (0 on a 429).X-RateLimit-Reset— seconds until the window resets. A duration, not a timestamp, so it needs no clock agreement.Retry-After— on a 429 only; seconds to wait. Never zero.
Over the limit the response is 429 with error code RATE_LIMITED. Honor
Retry-After — retrying sooner is refused and extends the window, since
the refused attempt is itself counted.
Service-level limits
Some resources meter the work itself rather than the request, and are
documented on the operation. They return 429 with their own error code
and no rate-limit headers, because the budget is not a per-endpoint window:
sending email is capped per (account, identity) per second
(EMAIL_RATE_LIMIT), and charge attempts are capped per invoice
(INVOICE_PAYMENT_ATTEMPTS_EXHAUSTED).
Path Parameters
"8f2a1c3d-4e5b-4a6f-9c0d-1e2f3a4b5c6d"
Body
Every field is optional; an omitted one is left alone, and sending none of them is a 400 rather than a silent no-op.
min_count and max_count are fixed at create and are not patchable.
The two tag sets move independently. tags relabels the pool itself and
takes effect immediately, touching no instance. template.tags — like the
rest of template — does NOT touch the instances already running: a live
VM cannot change flavor, tier, subnet or its tags in place. It changes what
the pool launches NEXT, so until you roll the pool it holds members
carrying two different tag sets, and stale_instance_count is how many are
on the older one. Bring them onto the current template with
POST /v1/instance-pools/{pool_id}/refresh.
REPLACES the pool's labels: the map you send becomes the whole set, an empty object clears them, and omitting the field leaves them alone. Replacement rather than a merge because a merge leaves no way to say a key should be removed.
These label the pool, not its instances. To change what future replicas are tagged with, send template.tags.
New target size, bounded by the pool's min_count/max_count and the hard platform cap of 100.
0 <= x <= 1003
Replaces the launch config WHOLESALE — the object you send is what the pool launches next, and anything you leave out is cleared rather than kept. Replacement rather than a deep merge so a shorter networks or data_volumes cannot be read as a truncation and silently drop an interface or a disk.
Response
The updated instance pool.
A launch template plus a desired count. Creating a pool spawns desired_count instances; a reconciler converges member_count toward desired_count as it changes. member_count is how many members the pool holds; live_count is how many of them are running.
A pool carries two tag sets and they answer different questions. tags labels the pool resource — that is what an IAM condition reads as basalt:ResourceTag/<key> and what a cost report groups by, and it reaches no instance. template.tags is the set stamped on every replica the pool launches.