REST API Endpoints:
http://localhost:15500
StreamableHTTP Endpoint:
http://localhost:15500/api/v1
Synap supports multiple request formats for improved SDK compatibility:
REST Endpoint: POST /hash/{key}/mset
Object Format (original):
{
"fields": {
"name": "Alice",
"age": 30,
"email": "alice@example.com"
}
}Array Format (SDK compatibility):
[
{"field": "name", "value": "Alice"},
{"field": "age", "value": 30},
{"field": "email", "value": "alice@example.com"}
]REST Endpoint: POST /kv/msetnx
Object Format (preferred):
{
"key": "user:1001",
"value": {"name": "Alice", "age": 30}
}Tuple Format (backward compatible):
["user:1001", {"name": "Alice", "age": 30}]REST Endpoint: POST /list/{key}/lpop or POST /list/{key}/rpop
With Count:
{
"count": 3
}Without Count (defaults to 1):
{}REST Endpoint: POST /sortedset/{key}/zadd
Single Member:
{
"member": "player1",
"score": 100.5
}Multiple Members (Redis-compatible):
{
"members": [
{"member": "player1", "score": 100.5},
{"member": "player2", "score": 200.0}
]
}REST Endpoint: GET /memory/{key}/usage
Returns {"bytes": 0, "human": "0B"} for non-existent keys instead of 404 error.
All requests require authentication via API key:
X-API-Key: synap_your_api_key_hereOr Bearer token:
Authorization: Bearer your_jwt_token_here{
"type": "response",
"request_id": "uuid",
"status": "success",
"payload": {
// Command-specific data
}
}{
"type": "response",
"request_id": "uuid",
"status": "error",
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message",
"details": {}
}
}POST /api/v1/command
{
"command": "kv.set",
"payload": {
"key": "user:1001",
"value": {"name": "Alice", "age": 30},
"ttl": 3600,
"nx": false,
"xx": false
}
}Parameters:
key(string): Key namevalue(any): Value to storettl(integer, optional): Time-to-live in secondsnx(boolean, optional): Only set if not existsxx(boolean, optional): Only set if exists
Response:
{
"status": "success",
"payload": {
"key": "user:1001",
"success": true,
"previous": null
}
}POST /api/v1/command
{
"command": "kv.get",
"payload": {
"key": "user:1001"
}
}Response:
{
"status": "success",
"payload": {
"found": true,
"value": {"name": "Alice", "age": 30},
"ttl": 3542
}
}POST /api/v1/command
{
"command": "kv.del",
"payload": {
"keys": ["user:1001", "user:1002"]
}
}Response:
{
"status": "success",
"payload": {
"deleted": 2
}
}POST /api/v1/command
{
"command": "kv.incr",
"payload": {
"key": "counter:views",
"amount": 1
}
}Response:
{
"status": "success",
"payload": {
"value": 42
}
}POST /api/v1/command
{
"command": "kv.scan",
"payload": {
"prefix": "user:",
"cursor": null,
"count": 100
}
}Response:
{
"status": "success",
"payload": {
"keys": ["user:1", "user:2", "user:3"],
"cursor": "next-page-token",
"has_more": true
}
}POST /api/v1/command
{
"command": "queue.publish",
"payload": {
"queue": "tasks",
"message": {
"type": "process_video",
"video_id": "vid_123"
},
"priority": 8,
"headers": {"source": "web-app"}
}
}Response:
{
"status": "success",
"payload": {
"message_id": "msg_abc123",
"position": 3
}
}POST /api/v1/command
{
"command": "queue.consume",
"payload": {
"queue": "tasks",
"timeout": 10,
"ack_deadline": 60
}
}Response:
{
"status": "success",
"payload": {
"message_id": "msg_abc123",
"message": {"type": "process_video", "video_id": "vid_123"},
"priority": 8,
"retry_count": 0,
"headers": {"source": "web-app"}
}
}POST /api/v1/command
{
"command": "queue.ack",
"payload": {
"queue": "tasks",
"message_id": "msg_abc123"
}
}Response:
{
"status": "success",
"payload": {
"success": true
}
}POST /api/v1/command
{
"command": "queue.nack",
"payload": {
"queue": "tasks",
"message_id": "msg_abc123",
"requeue": true
}
}Response:
{
"status": "success",
"payload": {
"success": true,
"action": "requeued"
}
}POST /api/v1/command
{
"command": "queue.stats",
"payload": {
"queue": "tasks"
}
}Response:
{
"status": "success",
"payload": {
"queue": "tasks",
"depth": 150,
"consumers": 5,
"published_total": 10000,
"consumed_total": 9850,
"acked_total": 9700,
"oldest_message_age_secs": 45
}
}POST /api/v1/command
{
"command": "stream.publish",
"payload": {
"room": "chat-room-1",
"event_type": "message",
"data": {
"user": "alice",
"text": "Hello everyone!"
}
}
}Response:
{
"status": "success",
"payload": {
"event_id": "evt_xyz789",
"offset": 42,
"subscribers_notified": 5
}
}WebSocket: ws://localhost:15500/api/v1/ws
Subscribe Message:
{
"command": "stream.subscribe",
"payload": {
"room": "chat-room-1",
"from_offset": null,
"replay": false
}
}Event Stream:
{"type": "event", "offset": 42, "event_type": "message", "data": {...}}
{"type": "event", "offset": 43, "event_type": "join", "data": {...}}POST /api/v1/command
{
"command": "stream.history",
"payload": {
"room": "chat-room-1",
"from_offset": 30,
"limit": 10
}
}Response:
{
"status": "success",
"payload": {
"events": [
{"offset": 30, "event_type": "message", "data": {...}},
{"offset": 31, "event_type": "join", "data": {...}}
],
"oldest_offset": 1,
"newest_offset": 42
}
}REST Endpoint: POST /pubsub/{topic}/publish
Request Body (supports both payload and data fields):
{
"payload": {
"to": "alice@example.com",
"subject": "Welcome!"
},
"metadata": {
"source": "web-app",
"priority": "high"
}
}Alternative format (SDK compatibility):
{
"data": {
"to": "alice@example.com",
"subject": "Welcome!"
}
}Note: The payload field is preferred, but data is accepted for SDK compatibility.
Response:
{
"subscribers_notified": 3
}StreamableHTTP Format: POST /api/v1/command
{
"command": "pubsub.publish",
"payload": {
"topic": "notifications.email.user",
"message": {
"to": "alice@example.com",
"subject": "Welcome!"
}
}
}WebSocket: ws://localhost:15500/api/v1/ws
Subscribe Message:
{
"command": "pubsub.subscribe",
"payload": {
"topics": ["notifications.email.*", "events.user.#"]
}
}Message Stream:
{"type": "message", "topic": "notifications.email.user", "message": {...}}
{"type": "message", "topic": "events.user.login", "message": {...}}POST /api/v1/command
{
"command": "admin.stats"
}Response:
{
"status": "success",
"payload": {
"server": {
"version": "0.1.0",
"uptime_secs": 86400,
"role": "master"
},
"memory": {
"used_bytes": 536870912,
"limit_bytes": 4294967296
},
"kv": {
"total_keys": 1000000,
"operations_per_sec": 50000
},
"queues": {
"total_queues": 50,
"total_messages": 5000
},
"streams": {
"total_rooms": 100,
"total_subscribers": 500
},
"pubsub": {
"total_topics": 200,
"total_subscribers": 1000
}
}
}GET /health
Response:
{
"status": "healthy",
"version": "0.1.0",
"role": "master",
"uptime_secs": 86400,
"components": {
"kv_store": "operational",
"queue_system": "operational",
"event_stream": "operational",
"pubsub": "operational",
"replication": "operational"
}
}GET /metrics
Response (Prometheus format):
# HELP synap_operations_total Total operations by type
# TYPE synap_operations_total counter
synap_operations_total{component="kv",operation="get"} 5000000
synap_operations_total{component="kv",operation="set"} 1000000
synap_operations_total{component="queue",operation="publish"} 100000
# HELP synap_memory_bytes Memory usage in bytes
# TYPE synap_memory_bytes gauge
synap_memory_bytes 536870912
# HELP synap_replication_lag_ms Replication lag in milliseconds
# TYPE synap_replication_lag_ms gauge
synap_replication_lag_ms{replica="replica-1"} 5
POST /api/v1/command
{
"type": "batch",
"request_id": "batch-001",
"commands": [
{
"command": "kv.set",
"payload": {"key": "user:1", "value": "data1"}
},
{
"command": "kv.set",
"payload": {"key": "user:2", "value": "data2"}
},
{
"command": "kv.get",
"payload": {"key": "user:1"}
}
]
}Response:
{
"type": "batch_response",
"request_id": "batch-001",
"results": [
{"status": "success", "payload": {"success": true}},
{"status": "success", "payload": {"success": true}},
{"status": "success", "payload": {"found": true, "value": "data1"}}
]
}Request:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999Response when limited:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1697410920
{
"status": "error",
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Try again in 60 seconds."
}
}GET /api/v1/ws
Upgrade Request:
GET /api/v1/ws HTTP/1.1
Host: localhost:15500
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
X-API-Key: synap_keySame command format as HTTP:
{
"request_id": "ws-001",
"command": "stream.subscribe",
"payload": {"room": "chat-1"}
}{
"type": "event",
"offset": 42,
"event_type": "message",
"data": {...}
}| Command | Description | Parameters |
|---|---|---|
kv.set |
Store key-value | key, value, ttl, nx, xx |
kv.get |
Retrieve value | key |
kv.del |
Delete keys | keys[] |
kv.exists |
Check existence | key |
kv.incr |
Increment | key, amount |
kv.decr |
Decrement | key, amount |
kv.expire |
Set TTL | key, ttl |
kv.ttl |
Get remaining TTL | key |
kv.scan |
Scan keys | prefix, cursor, count |
kv.mset |
Set multiple | pairs[] |
kv.mget |
Get multiple | keys[] |
| Command | Description | Parameters |
|---|---|---|
queue.create |
Create queue | queue, config |
queue.delete |
Delete queue | queue |
queue.publish |
Add message | queue, message, priority |
queue.consume |
Get message | queue, timeout, ack_deadline |
queue.ack |
Acknowledge | queue, message_id |
queue.nack |
Negative ack | queue, message_id, requeue |
queue.purge |
Clear queue | queue |
queue.stats |
Get statistics | queue |
queue.list |
List queues | - |
| Command | Description | Parameters |
|---|---|---|
stream.publish |
Publish event | room, event_type, data |
stream.subscribe |
Subscribe (WS) | room, from_offset, replay |
stream.unsubscribe |
Unsubscribe | room |
stream.history |
Get history | room, from_offset, limit |
stream.rooms |
List rooms | - |
stream.stats |
Room statistics | room |
| Command | Description | Parameters |
|---|---|---|
pubsub.publish |
Publish message | topic, message |
pubsub.subscribe |
Subscribe (WS) | topics[] |
pubsub.unsubscribe |
Unsubscribe | topics[] |
pubsub.topics |
List topics | pattern |
pubsub.stats |
Get statistics | - |
| Command | Description | Parameters |
|---|---|---|
admin.stats |
System stats | - |
admin.config |
Get config | - |
admin.health |
Health check | - |
admin.shutdown |
Graceful shutdown | - |
| Command | Description | Parameters |
|---|---|---|
replication.status |
Get status | - |
replication.promote |
Promote replica | force |
replication.resync |
Force resync | - |
| Status | Code | Usage |
|---|---|---|
| OK | 200 | Successful operation |
| Created | 201 | Resource created |
| No Content | 204 | Successful deletion |
| Bad Request | 400 | Invalid request format |
| Unauthorized | 401 | Invalid/missing API key |
| Forbidden | 403 | Insufficient permissions |
| Not Found | 404 | Resource not found |
| Conflict | 409 | Resource already exists |
| Payload Too Large | 413 | Request too large |
| Unprocessable Entity | 422 | Valid format, invalid data |
| Too Many Requests | 429 | Rate limit exceeded |
| Internal Server Error | 500 | Server error |
| Service Unavailable | 503 | Server overloaded |
| Insufficient Storage | 507 | Memory limit exceeded |
# 1. Create session
curl -X POST http://localhost:15500/api/v1/command \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{
"command": "kv.set",
"payload": {
"key": "session:abc123",
"value": {"user_id": 1, "logged_in": true},
"ttl": 3600
}
}'
# 2. Get session
curl -X POST http://localhost:15500/api/v1/command \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{
"command": "kv.get",
"payload": {"key": "session:abc123"}
}'
# 3. Delete session (logout)
curl -X POST http://localhost:15500/api/v1/command \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{
"command": "kv.del",
"payload": {"keys": ["session:abc123"]}
}'# 1. Publish task
curl -X POST http://localhost:15500/api/v1/command \
-d '{
"command": "queue.publish",
"payload": {
"queue": "tasks",
"message": {"type": "send_email", "to": "user@example.com"},
"priority": 5
}
}'
# 2. Consume task
curl -X POST http://localhost:15500/api/v1/command \
-d '{
"command": "queue.consume",
"payload": {"queue": "tasks", "timeout": 30}
}'
# 3. Acknowledge completion
curl -X POST http://localhost:15500/api/v1/command \
-d '{
"command": "queue.ack",
"payload": {"queue": "tasks", "message_id": "msg_123"}
}'Get current quota usage and limits for authenticated user.
Requires Hub Integration: This endpoint is only available when Synap is integrated with HiveHub.Cloud (hub.enabled: true).
Authentication: Required - Hub access key via Authorization: Bearer or X-Hub-Access-Key header
Request:
curl -X GET http://localhost:15500/hub/quota \
-H "Authorization: Bearer sk_live_a1b2c3d4e5f6..."Response:
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"plan": "Pro",
"quotas": {
"storage": {
"limit": 10737418240,
"used": 5368709120,
"available": 5368709120,
"percentage": 50.0
},
"operations": {
"limit": 10000000,
"used": 3456789,
"available": 6543211,
"percentage": 34.6,
"resets_at": "2025-02-01T00:00:00Z"
},
"connections": {
"limit": 100,
"active": 12,
"available": 88,
"percentage": 12.0
}
},
"restrictions": {
"max_ttl_seconds": 2592000,
"max_payload_bytes": 10485760,
"max_batch_size": 1000
}
}Response Fields:
user_id(string): UUID of the authenticated userplan(string): User's subscription plan (Free,Pro,Enterprise)quotas.storage(object): Storage quota informationlimit(number): Maximum storage in bytesused(number): Current storage used in bytesavailable(number): Remaining storage in bytespercentage(number): Usage percentage (0-100)
quotas.operations(object): Monthly operation quotalimit(number): Maximum operations per monthused(number): Operations used this monthavailable(number): Remaining operationspercentage(number): Usage percentage (0-100)resets_at(string): ISO 8601 timestamp when quota resets
quotas.connections(object): Connection quotalimit(number): Maximum concurrent connectionsactive(number): Currently active connectionsavailable(number): Available connection slotspercentage(number): Usage percentage (0-100)
restrictions(object): Plan-based restrictionsmax_ttl_seconds(number): Maximum TTL for resourcesmax_payload_bytes(number): Maximum payload sizemax_batch_size(number): Maximum batch operation size
Status Codes:
200 OK: Quota information returned successfully401 Unauthorized: Invalid or missing access key500 Internal Server Error: Failed to fetch quota from Hub API
Example - Free Plan:
{
"user_id": "123e4567-e89b-12d3-a456-426614174000",
"plan": "Free",
"quotas": {
"storage": {
"limit": 104857600,
"used": 52428800,
"available": 52428800,
"percentage": 50.0
},
"operations": {
"limit": 100000,
"used": 45000,
"available": 55000,
"percentage": 45.0,
"resets_at": "2025-02-01T00:00:00Z"
},
"connections": {
"limit": 10,
"active": 3,
"available": 7,
"percentage": 30.0
}
},
"restrictions": {
"max_ttl_seconds": 86400,
"max_payload_bytes": 1048576,
"max_batch_size": 100
}
}Example - Enterprise Plan:
{
"user_id": "789e0123-e45f-67g8-h901-234567890abc",
"plan": "Enterprise",
"quotas": {
"storage": {
"limit": 1099511627776,
"used": 549755813888,
"available": 549755813888,
"percentage": 50.0
},
"operations": {
"limit": null,
"used": 50000000,
"available": null,
"percentage": 0.0,
"resets_at": null
},
"connections": {
"limit": 1000,
"active": 250,
"available": 750,
"percentage": 25.0
}
},
"restrictions": {
"max_ttl_seconds": 31536000,
"max_payload_bytes": 104857600,
"max_batch_size": 10000
}
}Error Responses:
401 Unauthorized - Invalid access key:
{
"error": "Unauthorized",
"message": "Invalid or missing access key",
"code": "INVALID_ACCESS_KEY"
}500 Internal Server Error - Hub API failure:
{
"error": "InternalServerError",
"message": "Failed to fetch quota from Hub API: Connection timeout",
"code": "HUB_API_ERROR"
}Plan Comparison:
| Feature | Free | Pro | Enterprise |
|---|---|---|---|
| Storage Limit | 100 MB | 10 GB | 1 TB |
| Operations/Month | 100,000 | 10,000,000 | Unlimited |
| Concurrent Connections | 10 | 100 | 1,000 |
| Max TTL | 24 hours | 30 days | 365 days |
| Max Payload Size | 1 MB | 10 MB | 100 MB |
| Max Batch Size | 100 | 1,000 | 10,000 |
| Rate Limit | 10 req/s | 100 req/s | 1,000 req/s |
Notes:
- Quota data is cached for 60 seconds for performance
operations.limitisnullfor Enterprise plan (unlimited)operations.percentageis always 0.0 for Enterprise plan- Storage includes all data: queues, streams, KV store, data structures
- Operations count includes all read/write operations
- Connections count active persistent HTTP/2 connections
- Quota exceeded results in
429 Too Many Requestsresponses
Related Documentation:
- HUB_INTEGRATION.md - Complete Hub integration specification
- QUOTA_MANAGEMENT.md - Detailed quota system documentation
- ACCESS_KEYS.md - Access key authentication guide
- HUB_CONFIGURATION.md - Setup guide
- STREAMABLE_HTTP.md - Protocol specification
- PROTOCOL_MESSAGES.md - Message format details
- TYPESCRIPT.md - TypeScript SDK
- PYTHON.md - Python SDK