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.

Initiate an object upload into the bucket

POST
/scopes/{scopeId}/storage/buckets/{bucketId}/uploads

Initiates an object upload into the bucket, backing the "Upload" actions in the bucket detail header and the object-browser toolbar (uploads target the currently browsed prefix). The backend validates the destination, reserves the upload and returns a short-lived upload session with a presigned PUT URL the browser streams the file to. Once the upload completes, the object appears in the browser and the bucket's counters update. Validation: bucketId must reference an existing, non-deleted bucket in the scope (unknown → 404 NOT_FOUND); key is required and must be a valid, non-empty object key (optionally prefixed by the browsed folder); contentType must be a syntactically valid media type and sizeBytes a positive integer within the per-object size limit (invalid → 422 VALIDATION_FAILED); the subscription's storage quota must accommodate sizeBytes (exceeded → 409 QUOTA_EXCEEDED); a bucket in its deleting workflow rejects new uploads (→ 409 CONFLICT); caller must hold owner|admin|contributor on the scope, otherwise 403 FORBIDDEN. Async & state: Synchronous issuance — returns 200 with the BucketUploadSession; the data transfer itself then happens out-of-band against uploadUrl until expiresAt. When the object lands, a resource.updated SSE frame is emitted (kind storage.bucket, patch {objectCount, sizeBytes, updatedAt}) so open views refresh their counters. Errors: 401 unauthenticated; 403 caller lacks write permission on the scope; 404 unknown scopeId or bucketId; 409 CONFLICT bucket is mid-deletion; 409 CONFLICT details.reason=project_suspended the project's Temp-URL keys are withdrawn while it is suspended; 409 LOCKED the key already exists in a legacy delete-protected bucket (objectLock: true), an overwrite would replace it; 409 QUOTA_EXCEEDED storage quota cannot accommodate the declared size; 422 invalid key, content type or size (an invalid key carries details.reason=object_key_invalid and details.rule one of empty|too_long|control_char|folder|edge_unreachable; the key is the exact object name, never trimmed, at most 1024 UTF-8 bytes, and must not start with / or contain //, a ./.. segment, ; or \ -- the public object-store endpoint refuses such paths); 429 upload-session issuance rate limit exceeded; 500 unexpected backend failure. Signing key: the URL is signed with the account's Temp-URL-Key (slot 1). An existing slot-1 key -- including one the customer set -- is reused unchanged; only an account without one gets a key written, once. Slot 2 and container keys are never written. Idempotency/Concurrency: This operation does not use Idempotency-Key; it may be omitted and a sent one is ignored. Every call issues a new upload session (new uploadId, freshly signed uploadUrl, new expiresAt); nothing is reserved, so a retry simply yields another session for the same key. The presigned uploadUrl is revealed only in this response and never in any read model.

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.

bucketId*string

Identifier of the bucket.

Request Body

application/json
  1. body

Upload initiation payload (destination key plus declared media type and size).

key*string

Destination object key, including the browsed folder prefix when uploading inside one.

contentType*string
sizeBytes*integer

Declared size in bytes; an empty (0-byte) object is a valid upload.

Range0 <= value

Response Body

Upload session with a one-time presigned PUT URL.

application/json
  1. response

Short-lived upload session with a one-time presigned PUT URL.

uploadId*string
bucketId*string
key*string
uploadUrl*string

Presigned PUT URL to stream the file to (revealed only in this response).

method*"PUT"
Value in"PUT"
expiresAt*string
Formatdate-time
curl -X POST "https://example.com/scopes/string/storage/buckets/string/uploads" \  -H "Content-Type: application/json" \  -d '{    "key": "string",    "contentType": "string",    "sizeBytes": 0  }'
{  "uploadId": "string",  "bucketId": "string",  "key": "string",  "uploadUrl": "string",  "method": "PUT",  "expiresAt": "2019-08-24T14:15:22Z"}