Skip to content

Automate with the API

Write a small script that creates a volume, waits for it, and deletes it again. It shows the three habits every NubeStack Cloud integration needs: its own identity, an idempotency key per change, and following the operation to its end.

You will use: a service account, an API key, curl and jq.

1. Give the script its own identity

An owner or admin:

  1. Creates a service account ci-deploy, role Member.
  2. Gives it Project member on web-shop (in the project, IAM → People → Give access).
  3. Chooses Issue an API key, 90 days, and stores the key in your CI's secret store as NUBESTACK_API_KEY.

2. Find the IDs

export NUBESTACK_API="https://api.nubestack.cloud"   # placeholder: your API address
api() { curl -sS --fail-with-body -H "Authorization: Bearer $NUBESTACK_API_KEY" "$@"; }

ORG=$(api "$NUBESTACK_API/v1/me" | jq -r '.memberships[0].organization.id')
PROJECT=$(api "$NUBESTACK_API/v1/orgs/$ORG/projects" | jq -r '.items[] | select(.slug=="web-shop") | .id')
KHI=$(api "$NUBESTACK_API/v1/orgs/$ORG/locations" | jq -r '.items[] | select(.slug=="pak-khi-1") | .id')

Read sizes, images and volume types from the catalog rather than hard-coding them: GET /v1/orgs/$ORG/catalog?location=$KHI.

3. Make one change, safely

Choose the idempotency key once per change, and reuse it if you have to send the same request again after a network error. A new key per retry could create two volumes.

Sending a change again with the same idempotency key Your script sends a POST with the Idempotency-Key K to the NubeStack Cloud API. The connection drops and the answer is lost, so the script cannot tell whether the request arrived. It sends the request again with the same key K and the same body. The API answers with the first answer, marked Idempotency-Replayed: true, and nothing is made twice. Beside it, the cases that go wrong: the same key with a different body is refused with 409; a request without the Idempotency-Key header is refused with 428; and a new key for each retry could create two volumes. Use a new key for each new change, including a new attempt after a failed operation. Your script NubeStack Cloud API POST · Idempotency-Key: K the answer is lost Connection drops: did it arrive? Same key K, same body First answer · Idempotency-Replayed: true Nothing is made twice Refused or risky Same key, new body Refused with 409 No key header Refused with 428 A new key per retry Could create two volumes Use a new key for each new change, including after a failed operation.
One key per change, reused for every retry of that change.
KEY=$(uuidgen)
BODY=$(jq -n --arg loc "$KHI" '{location: $loc, display_name: "ci-scratch", size_gb: 10}')

for attempt in 1 2 3; do
  if RESP=$(api -X POST "$NUBESTACK_API/v1/orgs/$ORG/projects/$PROJECT/volumes" \
        -H "Idempotency-Key: $KEY" -H "Content-Type: application/json" -d "$BODY"); then
    break
  fi
  sleep $((attempt * 5))
done

OP=$(echo "$RESP" | jq -r .operation.id)
VOL=$(echo "$RESP" | jq -r .volume.id)

4. Wait for the operation

The life of an operation You send a change. NubeStack Cloud answers 202 Accepted with an operation in the state queued. The operation becomes running, then ends as succeeded, partially succeeded or failed. While it is still queued, it can be cancelled: cancelling, then cancelled. The end states never change. Your change 202 Accepted Queued Running Succeeded Partially succeeded Failed Cancelling Cancelled cancel The answer comes at once; the work runs in the location. End states never change
Acceptance and completion are separate. Keep the operation ID so a restarted script can carry on waiting.
deadline=$((SECONDS + 600))
while :; do
  STATE=$(api "$NUBESTACK_API/v1/orgs/$ORG/operations/$OP" | jq -r .state)
  case "$STATE" in
    succeeded) echo "volume $VOL ready"; break ;;
    partially_succeeded|failed|cancelled)
      api "$NUBESTACK_API/v1/orgs/$ORG/operations/$OP" | jq '.error, .steps'; exit 1 ;;
  esac
  [ $SECONDS -lt $deadline ] || { echo "still $STATE after 10 minutes"; exit 1; }
  sleep 5
done

A timeout in your script is not a cancellation: the operation goes on. Read it again before you make another change.

5. Clean up

api -X DELETE "$NUBESTACK_API/v1/orgs/$ORG/projects/$PROJECT/volumes/$VOL" \
  -H "Idempotency-Key: $(uuidgen)" | jq .operation

Habits to keep

  • One service account per pipeline, with only the projects and roles it needs.
  • On 429, wait the seconds in Retry-After. On 412, read the resource again before you retry.
  • Match errors on code, never on the message. See Errors.
  • Log request_id and operation IDs; they are what support needs.
  • Rotate the key before it expires.