Getting Started
Follow these steps to complete your first interactions with Oyster. By the end, you have created a bucket, uploaded a blob, and downloaded it back.
Prerequisites
- curl: for making HTTP requests to the JSON API
- AWS CLI (optional): for using the S3-compatible API (install guide)
Obtaining credentials
Oyster uses a two-tier auth model: operators manage accounts with
long-lived per-app admin keys, and end users authenticate data
operations with API keys. Both tiers use Authorization: Bearer <hex>;
the route prefix selects which credential table Oyster consults.
In this guide, the JSON API bucket and blob steps use an end-user API key, the operator sections use an admin key, and the AWS CLI steps use S3 access keys. Blob downloads through the JSON API need no credential.
For operators
The server operator creates an app, gets back a first admin key, and provisions accounts. See the Admin API docs for full details.
# 1. Create an app (server operator runs this once). `app new` auto-issues
# a first admin key by default; pass --no-key to opt out.
oysterd app new --name my-app --contact_email admin@example.com
# Prints: 550e8400-e29b-41d4-a716-446655440000 <- app id
# Prints: <64-char hex admin key> <- save this
export ADMIN_KEY="<64-char hex admin key from above>"
# 2. Create an account using the admin key
export OYSTER_URL="http://localhost:3000"
curl -s -X POST \
-H "Authorization: Bearer $ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "my-app-user"}' \
"$OYSTER_URL/api/v1/accounts" | jq
The response includes the account ID and an initial API key:
{
"account_id": "550e8400-e29b-41d4-a716-446655440000",
"api_key": {
"id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
"prefix": "a1b2c3d4",
"bearer_token": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
"created_at": "2025-01-15T10:30:00Z"
}
}
Save the account_id and bearer_token. Oyster shows the token only once.
export ACCOUNT_ID="550e8400-e29b-41d4-a716-446655440000"
export API_KEY="a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
For end users
Your operator provides you with an API key. Store it in an environment variable for the rest of this guide:
export OYSTER_URL="http://localhost:3000"
export API_KEY="your-api-key-here"
Create your first bucket
Buckets are named containers for your blobs. Create one called my-bucket:
curl -s -X POST \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "my-bucket"}' \
"$OYSTER_URL/api/v1/buckets" | jq
Response:
{
"name": "my-bucket",
"account_id": "550e8400-e29b-41d4-a716-446655440000",
"created_at": "2025-01-15T10:30:00Z"
}
Upload a blob
A blob is any data you store in a bucket under a key, such as a text file or an image. Oyster also gives each blob a content-addressed blob ID.
Upload a text file to your bucket with the key hello.txt:
curl -s -X PUT \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: text/plain" \
--data-binary "Hello, Oyster!" \
"$OYSTER_URL/api/v1/buckets/my-bucket/blobs/hello.txt" | jq
Response:
{
"key": "hello.txt",
"blob_id": "2cf24dba5fb0a30e...",
"size": 14,
"md5": "9a0364b9e99bb480...",
"sui_object_id": null,
"created_at": "2025-01-15T10:31:00Z"
}
You can also upload a file from disk:
curl -s -X PUT \
-H "Authorization: Bearer $API_KEY" \
--data-binary @photo.png \
"$OYSTER_URL/api/v1/buckets/my-bucket/blobs/images/photo.png" | jq
Download a blob
Blob reads are public (no authentication needed). Oyster serves a blob either by bucket name and key, as in the following example, or by its content-addressed blob ID at GET /api/v1/blobs/by-blob-id/{blob_id}:
curl -s "$OYSTER_URL/api/v1/buckets/my-bucket/blobs/hello.txt"
Output:
Hello, Oyster!
List blobs in a bucket
curl -s -H "Authorization: Bearer $API_KEY" \
"$OYSTER_URL/api/v1/buckets/my-bucket/blobs" | jq
Response:
{
"data": [
{
"key": "hello.txt",
"blob_id": "2cf24dba5fb0a30e...",
"bucket_name": "my-bucket",
"content_type": "text/plain",
"size": 14,
"md5": "9a0364b9e99bb480...",
"created_at": "2025-01-15T10:31:00Z"
}
],
"next_cursor": null
}
Delete a blob
curl -s -X DELETE \
-H "Authorization: Bearer $API_KEY" \
"$OYSTER_URL/api/v1/buckets/my-bucket/blobs/hello.txt"
Returns HTTP 204 (no content) on success.
Create additional API keys (operator)
The operator creates additional API keys through the Admin API using
admin-key authentication. This requires the $ADMIN_KEY and $ACCOUNT_ID
variables from the Obtaining Credentials section.
curl -s -X POST \
-H "Authorization: Bearer $ADMIN_KEY" \
"$OYSTER_URL/api/v1/accounts/$ACCOUNT_ID/api-keys" | jq
Response:
{
"id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
"prefix": "a1b2c3d4",
"bearer_token": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
"created_at": "2025-01-15T10:32:00Z"
}
Oyster shows the bearer_token field only once. Save it immediately.
See the Admin API docs for full details including error handling and key revocation.
AWS CLI version for the S3 API
To use the S3-compatible API from the command line, install AWS CLI v2. The S3 setup prerequisites list AWS CLI v2 for CLI usage. Other S3-compatible clients, such as boto3 or the AWS SDK for JavaScript, also work with Oyster.
Set up S3 access keys (operator)
To use the AWS CLI or any S3-compatible SDK, the operator creates S3 access
keys through the Admin API. This
requires the $ADMIN_KEY and $ACCOUNT_ID variables from the
Obtaining Credentials section.
curl -s -X POST \
-H "Authorization: Bearer $ADMIN_KEY" \
"$OYSTER_URL/api/v1/accounts/$ACCOUNT_ID/access-keys" | jq
Response:
{
"access_key_id": "OYAK1234567890ABCDEF",
"secret_access_key": "abcdef1234567890abcdef1234567890abcdef12",
"created_at": "2025-01-15T10:33:00Z"
}
Oyster shows the secret_access_key only once. Save it
immediately. You can have up to 3 active S3 access keys per account.
Then configure the AWS CLI (install AWS CLI v2 first, as described in AWS CLI version for the S3 API; older CLI versions do not support endpoint_url as a profile setting):
aws configure set aws_access_key_id "OYAK1234567890ABCDEF" --profile oyster
aws configure set aws_secret_access_key "abcdef1234567890..." --profile oyster
aws configure set region "us-east-1" --profile oyster
aws configure set endpoint_url "$OYSTER_URL" --profile oyster
Now you can use standard S3 commands:
# Create a bucket
aws --profile oyster s3api create-bucket --bucket my-s3-bucket
# Upload a file
aws --profile oyster s3api put-object \
--bucket my-s3-bucket --key hello.txt --body hello.txt
# Download a file
aws --profile oyster s3api get-object \
--bucket my-s3-bucket --key hello.txt downloaded.txt
For the full S3 API reference, see S3 API Reference.
What's next
- JSON API Reference: detailed documentation of every endpoint.
- S3 API Reference: complete S3-compatible operations and setup.
- Guides: CLI quick start, SDK examples, and advanced topics.
Who can download your blobs?
Anyone can download a blob through the JSON API without authentication, either by bucket name and key (GET /api/v1/buckets/{bucket_name}/blobs/{key}) or by its content-addressed blob ID (GET /api/v1/blobs/by-blob-id/{blob_id}). Only writes, deletes, and listing require an API key.
The S3-compatible API is different: all S3 operations, including reads, require SigV4 authentication. Because the same blob stays readable through the public JSON API routes, treat any content you upload as publicly readable.