Skip to content

Upload Endpoints

API endpoints for uploading Storybook builds.

Base URL

https://api.scry.com

Health Check

Check if the service is running.

http
GET /health

Response

json
{
  "status": "ok",
  "timestamp": "2024-01-15T10:30:00.000Z"
}

Direct Upload

Upload a zipped Storybook build directly to storage.

http
POST /upload/:project/:version

Authentication

Required. Include X-API-Key header.

Path Parameters

ParameterTypeDescription
projectstringProject identifier
versionstringVersion string

Headers

HeaderRequiredValue
X-API-KeyYesYour API key
Content-TypeYesapplication/zip

Request Body

Binary ZIP file data.

Response (201 Created)

json
{
  "success": true,
  "message": "Upload successful",
  "key": "my-project/v1.0.0/storybook.zip",
  "data": {
    "url": "https://pub-xxx.r2.dev/my-project/v1.0.0/storybook.zip",
    "path": "my-project/v1.0.0/storybook.zip",
    "versionId": "v1.0.0",
    "buildId": "abc123def456",
    "buildNumber": 42
  }
}

Example

bash
curl -X POST \
  -H "X-API-Key: scry_proj_my-project_xxx" \
  -H "Content-Type: application/zip" \
  --data-binary @storybook.zip \
  https://api.scry.com/upload/my-project/v1.0.0

Generate Presigned URL

Get a presigned URL for direct client-side upload to storage.

http
POST /presigned-url/:project/:version/:filename

Authentication

Required. Include X-API-Key header.

Path Parameters

ParameterTypeDescription
projectstringProject identifier
versionstringVersion string
filenamestringFile name (e.g., storybook.zip)

Headers

HeaderRequiredValue
X-API-KeyYesYour API key
Content-TypeYesMIME type of file to upload

Response (200 OK)

json
{
  "url": "https://xxx.r2.cloudflarestorage.com/bucket/path?X-Amz-...",
  "key": "my-project/v1.0.0/storybook.zip",
  "buildId": "abc123def456",
  "buildNumber": 42
}

Using the Presigned URL

bash
# 1. Get presigned URL
RESPONSE=$(curl -s -X POST \
  -H "X-API-Key: scry_proj_xxx" \
  -H "Content-Type: application/zip" \
  https://api.scry.com/presigned-url/my-project/v1.0.0/storybook.zip)

# 2. Extract URL
URL=$(echo $RESPONSE | jq -r '.url')

# 3. Upload directly to storage (no API key needed)
curl -X PUT \
  -H "Content-Type: application/zip" \
  --data-binary @storybook.zip \
  "$URL"

Get File Info

Check if a file exists and get its information.

http
GET /upload/:project/:version

Authentication

Not required.

Path Parameters

ParameterTypeDescription
projectstringProject identifier
versionstringVersion string

Response (200 OK)

json
{
  "project": "my-project",
  "version": "v1.0.0",
  "key": "my-project/v1.0.0/storybook.zip",
  "available": true
}

Response (404 Not Found)

json
{
  "project": "my-project",
  "version": "v1.0.0",
  "available": false
}

Error Responses

400 Bad Request

json
{
  "error": "Missing required parameter: project"
}

401 Unauthorized

json
{
  "error": "Authentication required"
}
json
{
  "error": "Invalid API key format"
}
json
{
  "error": "Invalid API key"
}

403 Forbidden

json
{
  "error": "Project mismatch",
  "message": "The API key does not belong to the requested project"
}

413 Payload Too Large

json
{
  "error": "File too large",
  "message": "Maximum upload size is 100 MB"
}

500 Internal Server Error

json
{
  "error": "Internal server error",
  "message": "Upload failed"
}

Limits

LimitValue
Maximum upload size100 MB
Presigned URL expiry15 minutes
Rate limit100 requests/minute per API key

Build Tracking

When Firestore is configured, uploads are tracked:

FieldDescription
buildIdUnique build identifier
buildNumberAuto-incrementing sequence number
projectIdProject identifier
versionIdVersion string
zipUrlPublic URL to the uploaded file
statusactive or archived
createdAtUpload timestamp

Released under the MIT License.