Upload Session Workflow
Uploading artifacts to Press.js Cloud follows a four-step protocol: create session → resolve missing blobs → upload blobs → commit. This allows efficient incremental uploads — only new files are transferred.
1. Create an upload session
Section titled “1. Create an upload session”Request: POST /v1/upload-sessions
curl -X POST "$PRESS_CLOUD_API/v1/upload-sessions" \ -H "Authorization: Bearer $PRESS_CLOUD_TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: upload-2026-04-28-001" \ -d '{ "deployId": "dpl_abc123", "files": [ { "path": "index.html", "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "size": 1024, "mime": "text/html" }, { "path": "assets/main.js", "sha256": "01ba4719c80b6fe911b091a7c05140b1b7b7e3c0b1e0b0b0b0b0b0b0b0b0b0b0b", "size": 65536, "mime": "application/javascript" } ] }'If the deploy does not yet exist, create it inline by passing createDeploy instead of deployId:
{ "createDeploy": { "slug": "my-document", "name": "My Document" }, "files": [ ... ]}Response: 201 Created
{ "uploadSession": { "id": "us_abc123", "status": "open", "requestedFileCount": 2, "requestedBytes": 66560, "createdAt": 1745800000000, "expiresAt": 1745803600000 }, "uploadToken": "ustk_L3pB6tY8jD5fG1cV0Hxq7sN2mK4vR9w"}Save the uploadToken — it is required for subsequent steps and is shown only once.
Error handling: A 409 with deploy_slug_conflict means the inline deploy slug is taken. A 400 with upload_session_too_large means the total bytes exceed plan limits (see limits).
2. Resolve missing blobs
Section titled “2. Resolve missing blobs”Before uploading, ask the server which files are already in storage. This avoids re-uploading unchanged artifacts.
Request: POST /v1/upload-sessions/{uploadSessionId}/missing-blobs
curl -X POST "$PRESS_CLOUD_API/v1/upload-sessions/us_abc123/missing-blobs" \ -H "Authorization: Bearer $PRESS_CLOUD_TOKEN" \ -H "Content-Type: application/json" \ -H "X-Upload-Token: ustk_L3pB6tY8jD5fG1cV0Hxq7sN2mK4vR9w" \ -d '{ "files": [ { "path": "index.html", "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "size": 1024, "mime": "text/html" }, { "path": "assets/main.js", "sha256": "01ba4719c80b6fe911b091a7c05140b1b7b7e3c0b1e0b0b0b0b0b0b0b0b0b0b0b", "size": 65536, "mime": "application/javascript" } ] }'Response: 200 OK
{ "uploadSessionId": "us_abc123", "missingBlobs": [ { "sha256": "01ba4719c80b6fe911b091a7c05140b1b7b7e3c0b1e0b0b0b0b0b0b0b0b0b0b0b" } ]}Only assets/main.js needs uploading — index.html is already in CAS storage.
Error handling: 410 if the session has expired (TTL is 1 hour). Create a new session and start over. 401 if the X-Upload-Token is missing or incorrect.
3. Upload missing blobs
Section titled “3. Upload missing blobs”Upload each missing blob by sha256. The request body is the raw file content (application/octet-stream).
Request: PUT /v1/upload-sessions/{uploadSessionId}/blobs/{sha256}
curl -X PUT "$PRESS_CLOUD_API/v1/upload-sessions/us_abc123/blobs/01ba4719c80b6fe911b091a7c05140b1b7b7e3c0b1e0b0b0b0b0b0b0b0b0b0b0b" \ -H "Authorization: Bearer $PRESS_CLOUD_TOKEN" \ -H "X-Upload-Token: ustk_L3pB6tY8jD5fG1cV0Hxq7sN2mK4vR9w" \ -H "Content-Type: application/octet-stream" \ --data-binary @assets/main.jsResponse: 200 OK
{ "uploadSessionId": "us_abc123", "alreadyPresent": false, "blob": { "sha256": "01ba4719c80b6fe911b091a7c05140b1b7b7e3c0b1e0b0b0b0b0b0b0b0b0b0b0b", "size": 65536, "r2Key": "cas/01ba47..." }}If the blob was already present (e.g., uploaded by a concurrent session), alreadyPresent is true and no data is re-stored.
Error handling: 400 with upload_blob_too_large if the file exceeds the plan’s max blob size. 409 if the sha256 does not match any file descriptor registered in the session.
4. Commit the session
Section titled “4. Commit the session”Finalize the upload session into an immutable deploy version. The entries array maps file paths to their blob hashes. The render config specifies the entry point for PDF rendering.
Request: POST /v1/upload-sessions/{uploadSessionId}/commit
curl -X POST "$PRESS_CLOUD_API/v1/upload-sessions/us_abc123/commit" \ -H "Authorization: Bearer $PRESS_CLOUD_TOKEN" \ -H "Content-Type: application/json" \ -H "X-Upload-Token: ustk_L3pB6tY8jD5fG1cV0Hxq7sN2mK4vR9w" \ -d '{ "entries": [ { "path": "index.html", "blobHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "size": 1024, "mime": "text/html" }, { "path": "assets/main.js", "blobHash": "01ba4719c80b6fe911b091a7c05140b1b7b7e3c0b1e0b0b0b0b0b0b0b0b0b0b0b", "size": 65536, "mime": "application/javascript" } ], "render": { "route": "/index.html", "title": "My Document", "renderTimeoutMs": 30000, "metadata": { "buildId": "ci-1234" } } }'Response: 201 Created
{ "deployVersion": { "id": "dv_456", "displayId": "#2", "deployId": "dpl_abc123", "versionNo": 2, "route": "/index.html", "title": "My Document", "status": "ready", "createdAt": 1745800300000 }}Next: Create a render job against this version (or point an alias to it first).
Error handling: 409 if the session is already committed or expired. 410 if the session TTL elapsed. 400 with deploy_commit_policy_limit_exceeded if the version exceeds file count or byte limits (see limits).