Store API
S3-backed object storage with org-scoped buckets, presigned URLs for direct browser uploads, and cursor-based pagination.
Buckets
Buckets are org-scoped containers. Each org can create multiple buckets to organize objects by purpose (uploads, avatars, exports, etc.).
| Method | Path | Description |
|---|---|---|
| GET | /v1/buckets | List all buckets for the org |
| POST | /v1/buckets | Create a new bucket |
SDK Examples
// List buckets
const buckets = await client.store.listBuckets();
// Create a bucket
const { bucket, created } = await client.store.createBucket({
name: 'user-uploads',
});
// Rust SDK
use kapable_sdk::store::types::*;
let buckets = client.store().list_buckets().await?;
let resp = client.store().create_bucket(CreateBucketRequest {
name: "user-uploads".into(),
}).await?;
Objects
Objects are files stored in buckets. Upload, download, list, delete, and inspect objects via the Objects endpoints.
| Method | Path | Description |
|---|---|---|
| GET | /v1/objects/{bucket} | List objects in a bucket (prefix filter, cursor pagination) |
| PUT | /v1/objects/{bucket}/{key} | Upload an object (raw bytes body) |
| GET | /v1/objects/{bucket}/{key} | Download an object |
| DELETE | /v1/objects/{bucket}/{key} | Delete an object |
| HEAD | /v1/objects/{bucket}/{key} | Get object metadata (size, content-type, etag) |
SDK Examples
// Upload a file
const data = new TextEncoder().encode('Hello, world!');
const uploaded = await client.store.uploadObject(
'user-uploads',
'docs/readme.txt',
data,
'text/plain',
);
console.log(`Uploaded: ${uploaded.key}, size: ${uploaded.size}`);
// Download a file
const response = await client.store.downloadObject(
'user-uploads',
'docs/readme.txt',
);
const text = await response.text();
// List objects with prefix
const listing = await client.store.listObjects('user-uploads', {
prefix: 'docs/',
max_keys: 100,
});
// Auto-paginate through all objects
for await (const obj of client.store.paginateObjects('user-uploads')) {
console.log(obj.key, obj.size);
}
// Delete an object
await client.store.deleteObject('user-uploads', 'docs/readme.txt');
// Rust SDK
let data = b"Hello, world!".to_vec();
let uploaded = client.store().upload_object(
"user-uploads", "docs/readme.txt", data, Some("text/plain"),
).await?;
let bytes = client.store().download_object(
"user-uploads", "docs/readme.txt",
).await?;
let listing = client.store().list_objects("user-uploads", ListObjectsParams {
prefix: Some("docs/".into()),
max_keys: Some(100),
..Default::default()
}).await?;
Presigned URLs
Generate presigned S3 URLs for direct browser uploads and downloads. This avoids proxying large files through the API server.
| Method | Path | Description |
|---|---|---|
| POST | /v1/presign/{bucket}/{key} | Generate a presigned upload URL |
| GET | /v1/presign/{bucket}/{key} | Generate a presigned download URL |
SDK Examples
// Get a presigned upload URL (browser can PUT directly to S3)
const { url, expires_at } = await client.store.presignUpload(
'user-uploads',
'photos/avatar.jpg',
{ expires_in: 3600 }, // 1 hour
);
// Browser-side upload using the presigned URL
await fetch(url, {
method: 'PUT',
body: fileBlob,
headers: { 'Content-Type': 'image/jpeg' },
});
// Get a presigned download URL
const download = await client.store.presignDownload(
'user-uploads',
'photos/avatar.jpg',
);
// Redirect user to download.url
The store service uses a separate S3 client for presigning that targets
the external endpoint (S3_EXTERNAL_ENDPOINT). This ensures
the presigned URL's signature matches the host the browser will connect to.