Storage

Preview — pending review

This reference is generated from the platform API contract and is still under review. Operations, fields, and descriptions can change before publication.

Accept a volume transfer offer into this project

POST
/scopes/{scopeId}/storage/volume-transfers/actions/accept

Called in the RECEIVING project's scope with the transferId and authKey the donor was given. On success the volume belongs to this project: the provider reassigns it, this API's inventory row follows, and billing follows with it. The tenant boundary is enforced here, not by the key. The provider would honour a key presented from anywhere in the cloud; this route refuses a transfer whose source volume does not sit under the SAME tenant as the accepting scope, and refuses it as 404 NOT_FOUND rather than 403 so an offer from another tenant is indistinguishable from one that does not exist. Billing. The hour bucket containing the acceptance belongs in full to the SOURCE subscription; the first bucket starting at or after it is the destination's. That is the same cut-over fixed for project moves, applied to one volume, and it is why usage is sealed against the source in the same transaction that flips the owner. No hour is split, duplicated or dropped. Validation: unknown or already-accepted transferId, a wrong authKey, and an offer from another tenant are ALL 404 NOT_FOUND — distinguishing them would let a caller probe for offers they cannot see. The receiving subscription's q-volumes / q-gigabytes quota must cover the volume (→ 409 QUOTA_EXCEEDED): accepting is the one way a project gains a volume without passing the create gate. Caller needs owner|admin|contributor on the receiving scope. Async & state: Asynchronous — 202 with an Operation. On completion the volume appears in this project's inventory and a resource.updated SSE frame (kind storage.volume) is emitted in the receiving scope. Errors: 401; 403; 404 unknown scope, unknown/spent offer, wrong key, or cross-tenant offer; 409 QUOTA_EXCEEDED; 422 malformed body; 500 provider failure. Idempotency/Concurrency: Idempotency-Key is optional (recommended); the replay returns the original 202. The offer itself is single-use at the provider, so two racing accepts cannot both win.

Authorization

bearerToken
headerAuthorizationBearer <token>

An API token (pc_live_…) or a service-account key (sak_live_…), created in Identity & Access Management and sent as Authorization: Bearer <token>. Requests are rate limited per credential and per tenant: every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset, and a refused request gets 429 RATE_LIMITED with Retry-After.

Path Parameters

scopeId*string

Opaque ownership+authorization scope resolving to tenant + subscription + project.

Header Parameters

Idempotency-Key?string

Optional; recommended for safe retries. When sent, the same key+body within 24h replays the original result and the same key with a different body is 409 CONFLICT; keys are unique per tenant. When an API token or service-account (bearer) caller omits it, the request is applied once with no replay protection (a retry may apply it again). A console session gets one from the edge.

Formatuuid

Request Body

application/json
  1. body

Payload for accepting a transfer offer into the calling scope's project.

transferId*string

Identifier of the offer, from the donor.

Length1 <= length <= 255
authKey*string

The one-shot authorization key the donor received when the offer was opened.

Length1 <= length <= 255

Response Body

Acceptance accepted; track it through the returned Operation.

application/json
  1. response

A long-running operation record. GET /operations/{operationId} returns its current state.

id*string

Operation identifier, unique platform-wide.

action*string

Canonical action id that started this operation, e.g. compute.instance.create.

state*OperationState

State machine for long-running operations. PENDING and RUNNING are transitional; the rest are terminal.

Value in"PENDING""RUNNING""SUCCEEDED""FAILED""CANCELLED"
resourceKind?|

Kind of the target resource (matches RealtimeEvent.kind), null for resource-less actions.

resourceId?|

Identifier of the target resource; null until the resource is allocated.

resourceName?|

Human-readable name of the target resource captured when the operation was opened; null when unknown or the resource has been deleted (clients fall back to resourceId).

principalId?|

Subject id (user id/email or service-account id) of the actor that initiated this operation, captured at the create chokepoint; null on internal/worker paths with no request-scoped principal or for historical rows. This is the real actor the Activity feed renders.

sourceIp?|

Source IP address of the request that initiated this operation; null when unavailable (internal/worker paths, historical rows).

progressPercent?|

Best-effort progress; null when the action does not report progress.

Range0 <= value <= 100
error?|null

Populated only when state is FAILED (or CANCELLED with partial rollback notes).

warning?|null

Non-fatal degradation recorded on an operation that still SUCCEEDED - the primary action completed but something explicitly requested could not be delivered (e.g. publicIp was requested at instance create but no floating IP could be assigned). On a CANCELLED create it reports that the provider resource had already been created and was kept (live and billed until deleted; details.disposition = left_in_place). Same code+message shape as error so clients render both uniformly; null when the operation ran without degradation.

startedAt?|

When the worker began executing; null while PENDING.

finishedAt?|

When a terminal state was reached; null while transitional.

createdAt*string
updatedAt*string
curl -X POST "https://example.com/scopes/string/storage/volume-transfers/actions/accept" \  -H "Content-Type: application/json" \  -d '{    "transferId": "string",    "authKey": "string"  }'
{  "id": "string",  "action": "string",  "state": "PENDING",  "resourceKind": "string",  "resourceId": "string",  "resourceName": "string",  "principalId": "string",  "sourceIp": "string",  "progressPercent": 0,  "error": {    "code": "string",    "message": "string",    "field": "string",    "details": {},    "retryable": false  },  "warning": {    "code": "string",    "message": "string",    "field": "string",    "details": {},    "retryable": false  },  "startedAt": "string",  "finishedAt": "string",  "createdAt": "string",  "updatedAt": "string"}