Skip to main content

Endpoint

POST https://storage-service.core.eachlabs.run/api/v1/uploads

Request Body

FieldTypeRequiredDescription
ownerstringYesYour organization identifier (format: org-<org-id>)
uploaderstringYesMust be "customer"
file_typestringNo"image", "video", "audio", or "other" (defaults to "other")
content_typestringNoMIME type of the file (e.g., "video/mp4", "image/png")
callback_urlstringNoWebhook URL to receive a notification when processing completes
audio_duration_secondsnumberNoDuration in seconds (audio files only)
video_duration_secondsnumberNoDuration in seconds (video files only)
video_bitrate_kbpsnumberNoBitrate in kbps (video files only)

Code Examples

curl -X POST https://storage-service.core.eachlabs.run/api/v1/uploads \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "owner": "org-your-org-id",
    "uploader": "customer",
    "file_type": "audio",
    "content_type": "audio/mp4"
  }'

Response

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "upload_url": "https://s3.us-east-1.amazonaws.com/bucket/uploads/550e8400.m4a?X-Amz-Algorithm=...",
  "public_url": "https://s3.us-east-1.amazonaws.com/bucket/uploads/550e8400.m4a",
  "expires_at": "2026-09-01T10:00:00Z",
  "status": "PENDING",
  "required_headers": {
    "Content-Type": "audio/mp4",
    "x-amz-meta-file-id": "550e8400-e29b-41d4-a716-446655440000",
    "x-amz-meta-expires-at": "2026-09-01T10:00:00Z",
    "x-amz-meta-audio-duration-seconds": "1008.32",
    "x-amz-tagging": "uploader=customer&ttl_days=30"
  }
}

Response Fields

FieldTypeDescription
idstringUnique file identifier (UUID). Use this for all subsequent requests.
upload_urlstringPresigned PUT URL. Valid for 15 minutes.
public_urlstringFinal URL where the file will be accessible after processing.
expires_atstringISO 8601 timestamp — when the file will be automatically deleted (default: 30 days).
statusstringInitial status is always "PENDING".
required_headersobjectHeaders you must include in the PUT request. See Upload File.

Error Responses

StatusCodeDescription
400BAD_REQUESTInvalid request body, missing required fields, or unsupported content type
401UNAUTHORIZEDMissing or invalid API key
500INTERNAL_ERRORUnexpected server error
{
  "status": 400,
  "error": "Human-readable error message",
  "code": "BAD_REQUEST",
  "request_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "details": {}
}

What Happens Next

After receiving the presigned URL, upload your file using a PUT request with the required_headers provided in the response.
The presigned URL expires after 15 minutes. If it expires, initiate a new upload.
Last modified on April 15, 2026