Skip to main content

API Overview

Safebucket provides a comprehensive REST API for programmatic access to file sharing functionality. The API is built with Go using the Chi router and follows RESTful conventions.

Base URL

The API is available at /api/v1/ from your Safebucket instance:

  • Local Development: http://localhost:8080/api/v1/
  • Production: https://yourdomain.com/api/v1/

Authentication

All API endpoints require authentication using JWT tokens.

Obtaining a Token

Local Authentication

POST /api/v1/auth/login
Content-Type: application/json

{
"email": "[email protected]",
"password": "password123"
}

Response:

{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "uuid",
"email": "[email protected]",
"first_name": "John",
"last_name": "Doe"
}
}

OIDC Authentication

OIDC authentication is handled through the web interface. Once authenticated, you can extract the JWT token from the session.

Using the Token

Include the JWT token in the Authorization header:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

API Endpoints

Authentication (/auth)

MethodEndpointDescription
POST/auth/loginLocal authentication
GET/auth/providersList OIDC providers
GET/auth/callback/{provider}OIDC callback
POST/auth/logoutLogout user

Users (/users)

MethodEndpointDescription
GET/users/meGet current user profile
PUT/users/meUpdate user profile
GET/usersList users (admin only)
GET/users/{id}Get user by ID

Buckets (/buckets)

MethodEndpointDescription
GET/bucketsList user's buckets
POST/bucketsCreate new bucket
GET/buckets/{id}Get bucket details
PUT/buckets/{id}Update bucket
DELETE/buckets/{id}Delete bucket
GET/buckets/{id}/filesList files in bucket
POST/buckets/{id}/uploadUpload file to bucket
GET/buckets/{id}/files/{fileId}Download file
DELETE/buckets/{id}/files/{fileId}Delete file

Invitations (/invites)

MethodEndpointDescription
POST/invitesCreate bucket invitation
GET/invitesList sent invitations
GET/invites/{id}Get invitation details
PUT/invites/{id}/acceptAccept invitation
PUT/invites/{id}/declineDecline invitation
DELETE/invites/{id}Cancel invitation

Request/Response Format

Content Types

  • Request Content-Type: application/json (except file uploads)
  • Response Content-Type: application/json
  • File Uploads: multipart/form-data

Standard Response Format

{
"data": []
}

Error Response Format

{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid input parameters",
"details": {
"field": "email",
"issue": "Invalid email format"
}
}
}

Common HTTP Status Codes

CodeMeaningDescription
200OKRequest successful
201CreatedResource created successfully
400Bad RequestInvalid request parameters
401UnauthorizedAuthentication required
403ForbiddenInsufficient permissions
404Not FoundResource not found
409ConflictResource already exists
422Unprocessable EntityValidation error
500Internal Server ErrorServer error

File Uploads

File uploads use multipart form data:

POST /api/v1/buckets/{id}/upload
Content-Type: multipart/form-data
Authorization: Bearer {token}

file: [binary file data]

Response:

{
"success": true,
"data": {
"file": {
"id": "file-uuid",
"name": "document.pdf",
"size": 1024000,
"content_type": "application/pdf",
"url": "https://storage.example.com/path/to/file",
"created_at": "2023-01-01T12:00:00Z"
}
}
}

Rate Limiting

The API implements rate limiting to prevent abuse:

  • Rate Limit: 100 requests per minute per IP
  • Headers: Rate limit information in response headers
    • X-RateLimit-Limit: Request limit
    • X-RateLimit-Remaining: Remaining requests
    • X-RateLimit-Reset: Reset timestamp

When rate limit is exceeded:

{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Try again later."
}
}

CORS

Cross-Origin Resource Sharing (CORS) is configured based on the APP__ALLOWED_ORIGINS setting:

# Allow specific origins
APP__ALLOWED_ORIGINS=http://localhost:3000,https://yourdomain.com

# Allow all origins (development only)
APP__ALLOWED_ORIGINS=*

SDK and Examples

cURL Examples

Login

curl -X POST http://localhost:1323/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"ChangeMePlease"}'

List Buckets

curl -X GET http://localhost:1323/api/v1/buckets \
-H "Authorization: Bearer YOUR_TOKEN"

Create Bucket

curl -X POST http://localhost:1323/api/v1/buckets \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"My Bucket","description":"Test bucket"}'

Upload File

curl -X POST http://localhost:1323/api/v1/buckets/BUCKET_ID/upload \
-H "Authorization: Bearer YOUR_TOKEN" \
-F "file=@/path/to/file.pdf"

JavaScript/Node.js

class SafeBucketAPI {
constructor(baseURL, token) {
this.baseURL = baseURL;
this.token = token;
}

async request(method, endpoint, data = null) {
const url = `${this.baseURL}/api/v1${endpoint}`;
const options = {
method,
headers: {
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json',
},
};

if (data) {
options.body = JSON.stringify(data);
}

const response = await fetch(url, options);
return response.json();
}

// Authentication
async login(email, password) {
const response = await fetch(`${this.baseURL}/api/v1/auth/login`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({email, password}),
});
const data = await response.json();
this.token = data.data.token;
return data;
}

// Buckets
async getBuckets() {
return this.request('GET', '/buckets');
}

async createBucket(name, description) {
return this.request('POST', '/buckets', {name, description});
}

async uploadFile(bucketId, file) {
const formData = new FormData();
formData.append('file', file);

const response = await fetch(`${this.baseURL}/api/v1/buckets/${bucketId}/upload`, {
method: 'POST',
headers: {'Authorization': `Bearer ${this.token}`},
body: formData,
});
return response.json();
}
}

// Usage
const api = new SafeBucketAPI('http://localhost:1323', null);
await api.login('[email protected]', 'ChangeMePlease');
const buckets = await api.getBuckets();

Python

import requests
import json


class SafeBucketAPI:
def __init__(self, base_url, token=None):
self.base_url = base_url
self.token = token
self.session = requests.Session()
if token:
self.session.headers.update({'Authorization': f'Bearer {token}'})

def login(self, email, password):
response = self.session.post(
f'{self.base_url}/api/v1/auth/login',
json={'email': email, 'password': password}
)
data = response.json()
self.token = data['data']['token']
self.session.headers.update({'Authorization': f'Bearer {self.token}'})
return data

def get_buckets(self):
response = self.session.get(f'{self.base_url}/api/v1/buckets')
return response.json()

def create_bucket(self, name, description=None):
data = {'name': name}
if description:
data['description'] = description

response = self.session.post(f'{self.base_url}/api/v1/buckets', json=data)
return response.json()

def upload_file(self, bucket_id, file_path):
with open(file_path, 'rb') as file:
files = {'file': file}
response = self.session.post(
f'{self.base_url}/api/v1/buckets/{bucket_id}/upload',
files=files
)
return response.json()


# Usage
api = SafeBucketAPI('http://localhost:1323')
api.login('[email protected]', 'ChangeMePlease')
buckets = api.get_buckets()

API Versioning

The API uses URL versioning (/api/v1/). Future versions will maintain backward compatibility where possible, with breaking changes requiring a new version path.

Support