Create snapshot policy
Attach a snapshot schedule to a volume. A volume has at most one policy; attaching a second is a 409.
The first snapshot lands one interval_minutes from now —
attaching a schedule is not itself a request for a snapshot. Use
POST /v1/snapshots for one now.
What retention can delete, since a schedule is also an automatic deleter: only the snapshots this policy itself took. A snapshot taken by hand is never reaped, and neither is one something depends on — a snapshot a volume was created from, including a restore still running, is skipped and looked at again later. Pausing the policy stops the deleting as well as the taking, and deleting the policy keeps every snapshot it already took.
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).
Headers
Optional client-generated key that makes a create replay-safe. Retrying a request with the same key returns the original outcome verbatim instead of creating a duplicate resource. Reusing a key with a different request body is rejected (422); a request whose key is still being processed returns 409. Records are honored for 24 hours. Use a UUID or similarly unique token.
255Body
"5f8d2c1a-9b3e-4d7a-8c6f-1e2a3b4c5d6e"
Unique within the account — it names the policy in its CRN.
Scheduled snapshots are named <policy>-<UTC timestamp>.
1 - 128"nightly"
Minutes between snapshots — a minimum gap, not an exact cadence. A
periodic pass takes whatever has come due and re-bases each policy's
next run off the moment it ran, so a snapshot lands at or after
interval_minutes and never before, and can land a minute or two
later when the pass is busy. A window the pass misses costs one
snapshot rather than producing a catch-up burst afterwards.
The floor is one minute, because that pass is what evaluates the
schedule and nothing finer can be honoured; the ceiling is 30 days.
Sub-hourly intervals multiply Ceph snapshot churn and count against
the snapshots quota, so pick the largest interval that meets your
recovery point objective.
1 <= x <= 432001440
How many of this policy's snapshots to keep. When a fire takes the count past this, the oldest go first.
1 <= x <= 2567
"Nightly snapshots of the database volume"
Optional age bound, applied on top of retention_count: a
snapshot outside EITHER window is reaped. 0 means no age bound.
The single newest snapshot is exempt from the age bound, so a
volume that could not be snapshotted for longer than the window
never loses its whole history.
0 <= x <= 365030
Defaults to true. Set false to attach a paused schedule. Pausing stops the whole policy — no snapshots are taken and none are deleted, because a paused schedule that kept reaping would delete history while you were looking at it.
true
Response
Snapshot policy created
A schedule attached to one volume: take a snapshot every
interval_minutes, then keep at most retention_count of the
snapshots this policy created.
Retention only ever deletes snapshots the policy itself created
(those carrying its snapshot_policy_id) — a snapshot taken by
hand is never reaped. It also never deletes a snapshot something
depends on: a snapshot a volume was created from, including a
restore still in progress, is skipped and re-examined later.