https://storage.<region>.basaltic.sh and can only attach to an instance in the
same region.
Create a volume
The two tiers you can provision on, and what each one gives you.
Attach and grow
Single-attach, what survives instance deletion, and the one state an
extend is accepted in.
Snapshots
Taking one, restoring from one, and why a volume with snapshots will not
delete.
Snapshot policies
Schedules, the two retention bounds, and what retention will never touch.
Creating a volume
Creation is asynchronous.POST /v1/volumes answers 202 with the volume
in creating; poll GET /v1/volumes/{volume_id} until status becomes
available or error.
unique within your account
Matches
^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$. It appears in the CRN, so it
has to be URL-safe. A duplicate name is 409 VOLUME_NAME_EXISTS.1–16384
required
The ceiling matches what a single block device is capped at elsewhere in the
industry. It is a per-volume sanity bound, not your quota — aggregate usage
is gated separately.
ssd | nvme
required
See below.
hdd exists as a stored tier but is rejected for new volumes:
the spinning-disk pool is reserved for cold object storage.Volume types
GET /v1/volume-types lists what you can provision on. The tier decides the
IO ceiling your volume gets, and that ceiling scales with size rather than
being flat — so the performance tracks what you paid for.
ssd
12 IOPS and 0.25 MiB/s per GB. Balanced cost against throughput.Floor 300 IOPS / 25 MiB/s, ceiling 16,000 IOPS / 250 MiB/s.
nvme
30 IOPS and 0.5 MiB/s per GB. Highest IOPS, lowest latency.Floor 1,000 IOPS / 50 MiB/s, ceiling 32,000 IOPS / 500 MiB/s.
The floors exist so a small volume is still usable, and the ceilings exist so
one large volume cannot consume a meaningful fraction of the tier on its own.
A single guest issuing enough concurrent IO can otherwise reach a
double-digit percentage of everything the tier serves.
Attaching to an instance
Attachment is a compute operation — the device binding, the guest hot-plug and the boot order all live on the instance side:available to in_use, and detaching puts it back to
available. See compute for the device slots, mount options and the
detach call.
What happens when the instance is deleted
Each attachment carries adelete_on_termination flag, and the default differs
by how the volume got there:
PATCH /v1/instances/{instance_id}/volumes/{volume_id} changes the flag on an
existing attachment. Set it deliberately on anything holding data you care
about — the boot volume default is the one that deletes.
The boot disk itself cannot be detached: unplugging it would take the guest’s
root filesystem with it, so the call is refused. Everything a boot volume cannot
do — extend included — follows from that.
Growing a volume
202 with the volume in extending and returns to
available at the new size. new_size_gb must be strictly greater than the
current size; anything else is 400 VOLUME_SIZE_INVALID.
Growing the volume does not grow the filesystem inside it. Once the volume is
bigger the guest sees the new size on its next device rescan, and expanding the
partition and filesystem is yours to do in the guest.
Deleting a volume
DELETE /v1/volumes/{volume_id} answers 202, flips the row to deleting
and tears the volume down asynchronously. Poll until the volume disappears.
Two refusals to know about:
409 VOLUME_IN_USE
409 VOLUME_IN_USE
The volume is attached. Detach it from the instance first. Delete is also
refused during the transient states —
creating, extending, deleting —
so a second operation cannot race the first.409 VOLUME_HAS_SNAPSHOTS
409 VOLUME_HAS_SNAPSHOTS
A volume that still has snapshots will not delete, because those snapshots
are children of the volume’s data and removing the parent underneath them
is not possible. Delete the snapshots first, then the volume.This is a clean refusal rather than a partial teardown, so nothing is lost
by trying.
Snapshots
A snapshot is a point-in-time copy of one volume:1
Take it
Allowed against a volume in
available or in_use — you do not have
to detach to snapshot. The snapshot is created asynchronously (202,
status creating).2
Wait for available
Poll
GET /v1/snapshots/{snapshot_id}. available means the snapshot is
complete and can be restored from; error puts the reason in
error_message.nightly on two different volumes
is fine. size_gb is the volume’s size frozen at the moment the snapshot was
taken — the volume may have been extended since, so do not read it as the
volume’s current size, and do not read it as the space the snapshot occupies.
Restoring from a snapshot
Restoring means creating a new volume from the snapshot. There is no in-place rollback:available, and size_gb must be at least the
snapshot’s frozen size — you can restore onto a larger volume, never a smaller
one. The restored volume records source_snapshot_id, which is also what stops
retention from reaping a snapshot something still depends on.
Snapshot policies
A policy is a schedule attached to one volume: take a snapshot everyinterval_minutes, then keep at most retention_count of the snapshots that
policy created.
one policy per volume
required
Attaching a second policy to the same volume is a
409. Update the existing
one instead.1–43200
required
A minimum gap, not an exact cadence. A snapshot lands at or after the
interval and never before, and can land a minute or two late when the
scheduling pass is busy. The floor is one minute because that is how often
the pass evaluates schedules; the ceiling is 30 days.
1–256
required
How many of this policy’s snapshots to keep. When a run takes the count past
this, the oldest go first.
0–3650, default 0
An optional age bound applied on top of the count: a snapshot outside
either window is reaped.
0 means no age bound.The first snapshot lands one interval from now. Attaching a schedule is not
itself a request for a snapshot — use
POST /v1/snapshots if you want one
immediately.<policy>-<UTC timestamp>, for example
nightly-20260115T000000Z, and they inherit the policy’s tags so a listing
tells you which schedule produced them without a second lookup.
What retention will never delete
A schedule is also an automatic deleter, so the limits on what it can remove matter more than the limits on what it keeps:Snapshots you took by hand
Retention only matches snapshots carrying this policy’s
snapshot_policy_id. A snapshot a person created has none and is never a
candidate, whatever tags it has.Snapshots something depends on
A snapshot a volume was created from — including a restore still running —
is skipped and re-examined on a later run. It becomes reapable once the
dependent volume is gone.
The single newest snapshot
The newest snapshot is exempt from the age bound. A volume that could
not be snapshotted for longer than the window never loses its whole
history that way.
Anything, while paused
enabled: false pauses the entire policy — no snapshots taken and none
deleted. A paused schedule that kept reaping would delete history while you
were looking at it.Reading a schedule’s state
GET /v1/snapshot-policies/{policy_id} returns where the policy is in its
cycle:
last_error is the field to check on a schedule that has stopped producing
snapshots — it carries reasons like an exhausted snapshots quota, or a volume
that was mid-extend when the window came around.
A missed window costs one snapshot, not one per window missed.
next_run_at is re-stamped to now + interval_minutes each time the policy
fires, never to previous + interval, so a schedule that could not run for
six hours takes a single snapshot when it resumes rather than a catch-up
burst. Changing interval_minutes re-bases the next run off now too, so
shortening a daily schedule to hourly takes effect within the hour.Volume statuses
Snapshots use a shorter set:
creating, available, deleting, error.
Quotas
Four storage counters, all scoped to your organization within a region:Quota is consumed for the lifetime of a row, not just while it is healthy. A
volume parked in
error still counts against volumes and
volume_storage_gb — which mirrors what you can see — so delete failed
volumes rather than leaving them.volume_storage_gb is refused up front rather than half-applied.
Naming, CRNs and tag-conditioned access
Volume, snapshot and snapshot-policy CRNs are built from the name, not the id, and carry the region and your account:crn:storage:*:my-account:volume/prod-* covers both the
volumes that exist and the ones that will.
All three resources accept a tags map, and the tag keys are policy context.
basalt:ResourceTag/<key> fences access to volumes already labelled a certain
way; basalt:RequestTag/<key> fences what a caller may label a volume as,
which is what makes a create authorizable before the volume exists:
Listing and pagination
Volumes, snapshots and policies are listed newest-first and paginated with an opaque cursor. Passmarker from the previous page’s meta to get the next
one:
name (case-insensitive substring) and
status; snapshots take volume_id to narrow to one volume, and policies take
volume_id and enabled.
Troubleshooting
Create rejected the volume type
Create rejected the volume type
hdd is a real tier but not a creatable one — its pool is reserved for
cold object storage. Use ssd or nvme. GET /v1/volume-types always
lists exactly what you may create on.Extend returns 409 VOLUME_NOT_AVAILABLE
Extend returns 409 VOLUME_NOT_AVAILABLE
The volume is not in
available. Attached volumes (in_use) are the
common case — detach, extend, re-attach. A volume mid-creating,
extending or deleting also refuses, and settles on its own.A boot volume can never reach available while its instance exists, so an
extend on one has no path to success. Move the data onto a separate volume,
or rebuild the instance with a larger boot volume.Delete returns 409 VOLUME_HAS_SNAPSHOTS
Delete returns 409 VOLUME_HAS_SNAPSHOTS
List them with
GET /v1/snapshots?volume_id=<id> and delete them first. If
a snapshot policy is still attached it may be creating new ones behind you
— delete the policy, or pause it with enabled: false, before clearing the
backlog.A snapshot policy has stopped taking snapshots
A snapshot policy has stopped taking snapshots
Read
last_error on the policy. The usual causes are an exhausted
snapshots quota — clear space by lowering retention_count or deleting
old snapshots — and a volume that was in a transient state when the window
came around, which resolves itself on the next run.A policy with enabled: false produces nothing at all, and next_run_at
tells you whether the schedule believes it is due.A restored volume came back the wrong size
A restored volume came back the wrong size
A restore clones the snapshot and then grows to the
size_gb you asked
for, so it is never smaller than the snapshot’s frozen size. The
filesystem inside it is still the size it was when the snapshot was taken —
expand it in the guest.Status is error
Status is error
error_message carries the last failure. The row keeps its quota while it
exists, so delete a volume or snapshot you do not intend to retry.Next
Object storage
Buckets, and the S3-compatible endpoint that serves them.
Compute
Attaching volumes, boot volumes and device slots.
Writing policies
Tag conditions and CRN patterns for storage resources.
API reference
Every storage operation, with request and response schemas.