Pubky Core API Reference
The Pubky Core protocol defines a RESTful HTTP API for storing and retrieving data on Homeservers. This document describes the complete API specification.
Base URL
All API endpoints are relative to the homeserver base URL:
https://homeserver.example.com
Homeserver URLs are discovered via PKARR records published to the Mainline DHT.
Authentication
See Authentication for conceptual overview.
Public Key Authentication
All requests must be authenticated using Ed25519 signatures:
Headers:
Authorization: Pubky <public_key>:<signature>:<timestamp>
Signature Generation:
- Create message:
METHOD:PATH:TIMESTAMP:BODY_HASH - Sign message with Ed25519 private key
- Encode signature as base64
Example (conceptual):
Method: PUT
Path: /pub/myapp/data
Timestamp: 1704067200
Body: {"hello":"world"}
Body Hash: sha256(body) = abc123...
Message to sign: "PUT:/pub/myapp/data:1704067200:abc123..."
Signature: sign_ed25519(message, private_key)
Authorization: Pubky 8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo:SGVsbG8gV29ybGQ=:1704067200
Session Tokens
For long-lived connections, use session tokens:
Request:
POST /auth/session
Authorization: Pubky <public_key>:<signature>:<timestamp>
Content-Type: application/json
{
"capabilities": [
"read:/pub/",
"write:/pub/myapp/"
],
"ttl": 3600
}Response:
{
"token": "session_abc123...",
"expires_at": 1704070800
}Usage:
GET /pub/myapp/data
Authorization: Bearer session_abc123...Storage Endpoints
PUT - Store Data
Store or update data at a path.
Request:
PUT /:path
Authorization: Pubky <public_key>:<signature>:<timestamp>
Content-Type: application/octet-stream
<binary data>Path Format:
- Must start with
/pub/(public) or/private/(future) - Maximum length: 1024 bytes
- Allowed characters:
a-z,A-Z,0-9,-,_,/,.
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"path": "/pub/myapp/data",
"size": 1234,
"created_at": 1704067200
}Error Responses:
400 Bad Request: Invalid path or data401 Unauthorized: Invalid authentication403 Forbidden: Insufficient permissions413 Payload Too Large: Data exceeds limit (default: 10MB)507 Insufficient Storage: Quota exceeded
GET - Retrieve Data
Retrieve data from a path.
Request:
GET /:path
Authorization: Pubky <public_key>:<signature>:<timestamp>Response:
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 1234
<binary data>Error Responses:
401 Unauthorized: Invalid authentication403 Forbidden: Insufficient permissions404 Not Found: Path does not exist
DELETE - Remove Data
Delete data at a path.
Request:
DELETE /:path
Authorization: Pubky <public_key>:<signature>:<timestamp>Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"path": "/pub/myapp/data",
"deleted_at": 1704067200
}Error Responses:
401 Unauthorized: Invalid authentication403 Forbidden: Insufficient permissions404 Not Found: Path does not exist
LIST - Enumerate Data
List entries under a path prefix (with pagination).
Request:
GET /:path?limit=20&cursor=abc123&reverse=false
Authorization: Pubky <public_key>:<signature>:<timestamp>Query Parameters:
limit(optional): Maximum entries to return (default: 100, max: 1000)cursor(optional): Pagination cursor from previous responsereverse(optional): List in reverse order (newest first)
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"entries": [
{
"path": "/pub/myapp/posts/001",
"size": 512,
"created_at": 1704067200,
"updated_at": 1704067200
},
{
"path": "/pub/myapp/posts/002",
"size": 1024,
"created_at": 1704067300,
"updated_at": 1704067300
}
],
"cursor": "next_page_cursor_xyz",
"has_more": true
}Error Responses:
401 Unauthorized: Invalid authentication403 Forbidden: Insufficient permissions
Capabilities System
Capabilities define what operations a session can perform:
Capability Syntax
<operation>:<path_prefix>
Operations:
read: GET, LIST operationswrite: PUT, DELETE operations*: All operations
Examples:
read:/pub/ # Read all public data
write:/pub/myapp/ # Write to /pub/myapp/* only
*:/pub/myapp/posts/ # Full access to posts
read:/pub/social/profile # Read specific path
Capability Checking
When a request is made:
- Check session capabilities
- Match requested path against capability patterns
- Verify operation is allowed
- Execute or deny request
Event Streaming (Future)
Subscribe to real-time updates on data changes.
Request:
GET /events?paths=/pub/myapp/&since=1704067200
Authorization: Bearer session_abc123...Response (Server-Sent Events):
HTTP/1.1 200 OK
Content-Type: text/event-stream
event: created
data: {"path":"/pub/myapp/posts/003","size":256,"timestamp":1704067400}
event: updated
data: {"path":"/pub/myapp/profile","size":512,"timestamp":1704067500}
event: deleted
data: {"path":"/pub/myapp/temp","timestamp":1704067600}Admin Endpoints
Homeserver administrators can access management endpoints:
GET /admin/stats
Get server statistics.
Response:
{
"users": 1000,
"total_storage": 1073741824,
"requests_per_minute": 150,
"uptime_seconds": 86400
}GET /admin/users/:public_key
Get user information.
Response:
{
"public_key": "8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo",
"storage_used": 10485760,
"storage_quota": 104857600,
"created_at": 1704000000,
"last_activity": 1704067200
}See Admin API for complete admin documentation.
Metrics Endpoint
Prometheus-compatible metrics for monitoring.
GET /metrics
Response:
# HELP pubky_requests_total Total HTTP requests
# TYPE pubky_requests_total counter
pubky_requests_total{method="GET",status="200"} 1000
pubky_requests_total{method="PUT",status="200"} 500
# HELP pubky_storage_bytes Total storage used
# TYPE pubky_storage_bytes gauge
pubky_storage_bytes 1073741824
# HELP pubky_active_sessions Current active sessions
# TYPE pubky_active_sessions gauge
pubky_active_sessions 50
Rate Limiting
Homeservers implement rate limiting to prevent abuse:
Headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1704067260Rate Limit Exceeded:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{
"error": "rate_limit_exceeded",
"message": "Too many requests, try again in 60 seconds"
}Default Limits:
- Anonymous: 10 requests/minute
- Authenticated: 100 requests/minute
- Admin: Unlimited
Error Responses
All errors follow a consistent format:
{
"error": "error_code",
"message": "Human-readable error message",
"details": {
"additional": "context"
}
}Common Error Codes:
invalid_path: Path format is invalidinvalid_signature: Authentication signature invalidexpired_session: Session token expiredinsufficient_permissions: Operation not allowedstorage_quota_exceeded: User quota exceededrate_limit_exceeded: Too many requestsserver_error: Internal server error
Best Practices
Efficient List Operations
Paginate large datasets:
async function getAllPosts(client, publicKey) {
const allPosts = [];
let cursor = null;
do {
const response = await client.list(
`pubky://${publicKey}/pub/myapp/posts/`,
{ limit: 100, cursor }
);
allPosts.push(...response.entries);
cursor = response.cursor;
} while (response.has_more);
return allPosts;
}Optimize Storage
Store structured data efficiently:
// Good: Separate entries for each post
PUT /pub/myapp/posts/001 (small JSON)
PUT /pub/myapp/posts/002 (small JSON)
PUT /pub/myapp/posts/003 (small JSON)
// Bad: Single large entry
PUT /pub/myapp/all_posts (large JSON array)Handle Errors Gracefully
async function robustPut(client, path, data) {
const maxRetries = 3;
for (let i = 0; i < maxRetries; i++) {
try {
return await client.put(path, data);
} catch (error) {
if (error.code === 'rate_limit_exceeded') {
await sleep(error.retryAfter * 1000);
continue;
}
throw error;
}
}
}Resources
- Pubky Core Overview: Main documentation
- SDK Documentation: Client libraries
- Homeserver Documentation: Server setup
- Official Docs: pubky.github.io/pubky-core
- Repository: github.com/pubky/pubky-core
The Pubky Core API provides a simple, RESTful interface for decentralized data storage.