sdk_relay/docs/API.md
Nicolas Cantu f2b20aee77
Some checks failed
CI - sdk_relay / build-test (push) Failing after 33s
CI - sdk_relay / security (push) Successful in 2m2s
Documentation API: refonte technique avec flux JSON détaillés et exemples de requêtes/réponses
2025-08-25 15:25:19 +02:00

1257 lines
27 KiB
Markdown

# API Reference - sdk_relay
## Vue d'Ensemble
`sdk_relay` expose deux interfaces principales :
- **WebSocket API** (port 8090) : Communication temps réel bidirectionnelle
- **HTTP REST API** (port 8091) : Interface REST pour les opérations CRUD
## Base URLs
```bash
# WebSocket
ws://localhost:8090
wss://localhost:8090 # Sécurisé
# HTTP REST
http://localhost:8091
https://localhost:8091 # Sécurisé
```
---
## WebSocket API - Flux de Messages
### 1. Connexion et Handshake
**Flux de connexion :**
```
Client → WebSocket Connection → sdk_relay
Client → Handshake Message → sdk_relay
sdk_relay → Handshake Response → Client
```
**Message de Handshake (Client → sdk_relay) :**
```json
{
"type": "handshake",
"client_id": "my-client-123",
"version": "1.0.0",
"capabilities": ["sync", "notifications", "health"],
"timestamp": 1703001600
}
```
**Réponse de Handshake (sdk_relay → Client) :**
```json
{
"type": "handshake_response",
"status": "accepted",
"relay_id": "relay-1",
"version": "1.0.0",
"capabilities": ["sync", "notifications", "health", "metrics"],
"timestamp": 1703001600
}
```
### 2. Messages de Synchronisation
#### StateSync
**Flux :**
```
relay-1 → StateSync → relay-2
relay-2 → StateSync Response → relay-1
```
**Message StateSync (relay-1 → relay-2) :**
```json
{
"type": "sync",
"sync_type": "StateSync",
"relay_id": "relay-1",
"payload": {
"state": {
"uptime": 3600,
"version": "1.0.0",
"network": "signet",
"status": "healthy",
"last_block": 12345,
"connections": 5,
"known_relays": 3,
"mesh_connections": 6
}
},
"timestamp": 1703001600,
"message_id": "msg-123"
}
```
**Réponse StateSync (relay-2 → relay-1) :**
```json
{
"type": "sync_response",
"sync_type": "StateSync",
"relay_id": "relay-2",
"payload": {
"state": {
"uptime": 1800,
"version": "1.0.0",
"network": "signet",
"status": "healthy",
"last_block": 12345,
"connections": 3,
"known_relays": 3,
"mesh_connections": 6
}
},
"timestamp": 1703001600,
"message_id": "msg-124"
}
```
#### HealthSync
**Flux :**
```
relay-1 → HealthSync → relay-2
relay-2 → HealthSync Response → relay-1
```
**Message HealthSync (relay-1 → relay-2) :**
```json
{
"type": "sync",
"sync_type": "HealthSync",
"relay_id": "relay-1",
"payload": {
"health": {
"status": "healthy",
"memory_usage": "128MB",
"cpu_usage": "5%",
"disk_usage": "2GB",
"network_latency": 45,
"error_count": 0,
"last_error": null
}
},
"timestamp": 1703001600,
"message_id": "msg-125"
}
```
**Réponse HealthSync (relay-2 → relay-1) :**
```json
{
"type": "sync_response",
"sync_type": "HealthSync",
"relay_id": "relay-2",
"payload": {
"health": {
"status": "healthy",
"memory_usage": "96MB",
"cpu_usage": "3%",
"disk_usage": "1.5GB",
"network_latency": 32,
"error_count": 0,
"last_error": null
}
},
"timestamp": 1703001600,
"message_id": "msg-126"
}
```
#### MetricsSync
**Flux :**
```
relay-1 → MetricsSync → relay-2
relay-2 → MetricsSync Response → relay-1
```
**Message MetricsSync (relay-1 → relay-2) :**
```json
{
"type": "sync",
"sync_type": "MetricsSync",
"relay_id": "relay-1",
"payload": {
"metrics": {
"known_relays": 3,
"mesh_connections": 6,
"sync_requests": 150,
"sync_responses": 150,
"cache_hits": 120,
"cache_misses": 30,
"avg_latency": 45.2,
"error_count": 0,
"success_rate": 98.67,
"messages_per_second": 2.5
}
},
"timestamp": 1703001600,
"message_id": "msg-127"
}
```
**Réponse MetricsSync (relay-2 → relay-1) :**
```json
{
"type": "sync_response",
"sync_type": "MetricsSync",
"relay_id": "relay-2",
"payload": {
"metrics": {
"known_relays": 3,
"mesh_connections": 6,
"sync_requests": 120,
"sync_responses": 120,
"cache_hits": 95,
"cache_misses": 25,
"avg_latency": 38.5,
"error_count": 0,
"success_rate": 100.0,
"messages_per_second": 2.0
}
},
"timestamp": 1703001600,
"message_id": "msg-128"
}
```
### 3. Messages de Notification
#### Payment Detected
**Flux :**
```
sdk_relay → Payment Notification → Client
```
**Message Payment Detected (sdk_relay → Client) :**
```json
{
"type": "notification",
"notification_type": "payment_detected",
"data": {
"txid": "abc123def456789abcdef456789abcdef456789abc",
"block_height": 12345,
"block_hash": "def789abc123456def789abc123456def789abc123",
"amount": "0.001",
"address": "sp1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
"confirmations": 1,
"timestamp": 1703001600,
"fee": "0.00001",
"size": 250
},
"timestamp": 1703001600
}
```
#### Block Mined
**Flux :**
```
sdk_relay → Block Notification → Client
```
**Message Block Mined (sdk_relay → Client) :**
```json
{
"type": "notification",
"notification_type": "block_mined",
"data": {
"block_height": 12346,
"block_hash": "ghi012jkl345678ghi012jkl345678ghi012jkl345",
"transactions": 150,
"size": 1024000,
"timestamp": 1703001600,
"difficulty": 1.0,
"merkle_root": "abc123def456789abcdef456789abcdef456789abc"
},
"timestamp": 1703001600
}
```
#### Relay Connected
**Flux :**
```
sdk_relay → Relay Notification → Client
```
**Message Relay Connected (sdk_relay → Client) :**
```json
{
"type": "notification",
"notification_type": "relay_connected",
"data": {
"relay_id": "relay-4",
"address": "relay-4.example.com:8090",
"version": "1.0.0",
"capabilities": ["sync", "notifications"],
"timestamp": 1703001600,
"connection_id": "conn-456"
},
"timestamp": 1703001600
}
```
### 4. Messages de Contrôle
#### Ping/Pong
**Flux :**
```
Client → Ping → sdk_relay
sdk_relay → Pong → Client
```
**Message Ping (Client → sdk_relay) :**
```json
{
"type": "ping",
"client_id": "my-client-123",
"timestamp": 1703001600
}
```
**Message Pong (sdk_relay → Client) :**
```json
{
"type": "pong",
"relay_id": "relay-1",
"timestamp": 1703001600
}
```
#### Subscribe/Unsubscribe
**Flux :**
```
Client → Subscribe → sdk_relay
sdk_relay → Subscribe Response → Client
```
**Message Subscribe (Client → sdk_relay) :**
```json
{
"type": "subscribe",
"subscriptions": ["notifications", "health", "metrics"],
"client_id": "my-client-123",
"timestamp": 1703001600
}
```
**Réponse Subscribe (sdk_relay → Client) :**
```json
{
"type": "subscribe_response",
"status": "subscribed",
"subscriptions": ["notifications", "health", "metrics"],
"relay_id": "relay-1",
"timestamp": 1703001600
}
```
**Message Unsubscribe (Client → sdk_relay) :**
```json
{
"type": "unsubscribe",
"subscriptions": ["metrics"],
"client_id": "my-client-123",
"timestamp": 1703001600
}
```
**Réponse Unsubscribe (sdk_relay → Client) :**
```json
{
"type": "unsubscribe_response",
"status": "unsubscribed",
"subscriptions": ["notifications", "health"],
"relay_id": "relay-1",
"timestamp": 1703001600
}
```
---
## HTTP REST API - Flux de Requêtes
### 1. Health Check
**Flux :**
```
Client → GET /health → sdk_relay
sdk_relay → Health Response → Client
```
**Requête :**
```http
GET /health HTTP/1.1
Host: localhost:8091
User-Agent: curl/7.68.0
Accept: application/json
```
**Réponse :**
```json
{
"status": "healthy",
"uptime": 3600,
"version": "1.0.0",
"timestamp": 1703001600,
"services": {
"bitcoin_core": "connected",
"blindbit": "connected",
"websocket": "listening",
"sync_manager": "active"
},
"checks": {
"bitcoin_rpc": true,
"blindbit_api": true,
"websocket_server": true,
"sync_manager": true
}
}
```
### 2. Métriques
**Flux :**
```
Client → GET /metrics → sdk_relay
sdk_relay → Metrics Response → Client
```
**Requête :**
```http
GET /metrics HTTP/1.1
Host: localhost:8091
User-Agent: curl/7.68.0
Accept: application/json
```
**Réponse :**
```json
{
"sync_metrics": {
"known_relays": 3,
"mesh_connections": 6,
"sync_requests": 150,
"sync_responses": 150,
"cache_hits": 120,
"cache_misses": 30,
"avg_latency": 45.2,
"error_count": 0,
"success_rate": 98.67
},
"system_metrics": {
"memory_usage": "128MB",
"cpu_usage": "5%",
"active_connections": 10,
"total_requests": 1000,
"uptime": 3600
},
"bitcoin_metrics": {
"block_height": 12345,
"connections": 8,
"mempool_size": 150,
"verification_progress": 0.9999
},
"timestamp": 1703001600
}
```
### 3. Configuration
**Flux :**
```
Client → GET /config → sdk_relay
sdk_relay → Config Response → Client
```
**Requête :**
```http
GET /config HTTP/1.1
Host: localhost:8091
User-Agent: curl/7.68.0
Accept: application/json
```
**Réponse :**
```json
{
"relay_id": "relay-1",
"network": "signet",
"ws_url": "0.0.0.0:8090",
"http_url": "0.0.0.0:8091",
"bitcoin_core": {
"url": "http://bitcoin:18443",
"wallet": "relay_wallet",
"zmq_url": "tcp://bitcoin:29000"
},
"blindbit": {
"url": "http://blindbit:8000"
},
"sync": {
"interval": 30,
"health_interval": 60,
"metrics_interval": 120
},
"dev_mode": true,
"standalone": false,
"timestamp": 1703001600
}
```
### 4. Liste des Relais
**Flux :**
```
Client → GET /relays → sdk_relay
sdk_relay → Relays Response → Client
```
**Requête :**
```http
GET /relays?status=healthy&limit=10 HTTP/1.1
Host: localhost:8091
User-Agent: curl/7.68.0
Accept: application/json
```
**Réponse :**
```json
{
"relays": [
{
"relay_id": "relay-1",
"address": "sdk_relay_1:8090",
"version": "1.0.0",
"uptime": 3600,
"health": "healthy",
"last_seen": 1703001600,
"capabilities": ["sync", "notifications", "health"],
"connections": 5,
"metrics": {
"sync_requests": 50,
"sync_responses": 50,
"avg_latency": 45.2
}
},
{
"relay_id": "relay-2",
"address": "sdk_relay_2:8090",
"version": "1.0.0",
"uptime": 1800,
"health": "healthy",
"last_seen": 1703001600,
"capabilities": ["sync", "notifications"],
"connections": 3,
"metrics": {
"sync_requests": 30,
"sync_responses": 30,
"avg_latency": 38.5
}
}
],
"total": 2,
"healthy": 2,
"warning": 0,
"critical": 0,
"timestamp": 1703001600
}
```
### 5. Détails d'un Relais
**Flux :**
```
Client → GET /relays/{relay_id} → sdk_relay
sdk_relay → Relay Details Response → Client
```
**Requête :**
```http
GET /relays/relay-1 HTTP/1.1
Host: localhost:8091
User-Agent: curl/7.68.0
Accept: application/json
```
**Réponse :**
```json
{
"relay_id": "relay-1",
"address": "sdk_relay_1:8090",
"version": "1.0.0",
"uptime": 3600,
"health": "healthy",
"last_seen": 1703001600,
"capabilities": ["sync", "notifications", "health"],
"connections": 5,
"metrics": {
"sync_requests": 50,
"sync_responses": 50,
"avg_latency": 45.2,
"error_count": 0,
"success_rate": 100.0
},
"configuration": {
"network": "signet",
"dev_mode": true,
"sync_interval": 30
},
"status": {
"bitcoin_connected": true,
"blindbit_connected": true,
"websocket_listening": true,
"sync_active": true
},
"timestamp": 1703001600
}
```
### 6. Statut de Synchronisation
**Flux :**
```
Client → GET /sync/status → sdk_relay
sdk_relay → Sync Status Response → Client
```
**Requête :**
```http
GET /sync/status HTTP/1.1
Host: localhost:8091
User-Agent: curl/7.68.0
Accept: application/json
```
**Réponse :**
```json
{
"status": "syncing",
"last_sync": 1703001600,
"next_sync": 1703001630,
"sync_types": [
"StateSync",
"HealthSync",
"MetricsSync"
],
"errors": [],
"statistics": {
"total_syncs": 150,
"successful_syncs": 148,
"failed_syncs": 2,
"success_rate": 98.67,
"avg_duration": 45.2
},
"active_syncs": [
{
"sync_type": "StateSync",
"target_relay": "relay-2",
"started": 1703001600,
"status": "in_progress"
}
],
"timestamp": 1703001600
}
```
### 7. Forcer la Synchronisation
**Flux :**
```
Client → POST /sync/force → sdk_relay
sdk_relay → Force Sync Response → Client
```
**Requête :**
```http
POST /sync/force HTTP/1.1
Host: localhost:8091
User-Agent: curl/7.68.0
Content-Type: application/json
Accept: application/json
```
**Réponse :**
```json
{
"status": "sync_triggered",
"sync_types": ["StateSync", "HealthSync"],
"target_relays": ["relay-2", "relay-3"],
"timestamp": 1703001600,
"estimated_duration": "30s",
"sync_id": "sync-789"
}
```
### 8. Historique des Synchronisations
**Flux :**
```
Client → GET /sync/history → sdk_relay
sdk_relay → Sync History Response → Client
```
**Requête :**
```http
GET /sync/history?limit=10&since=1703000000&sync_type=StateSync HTTP/1.1
Host: localhost:8091
User-Agent: curl/7.68.0
Accept: application/json
```
**Réponse :**
```json
{
"history": [
{
"timestamp": 1703001600,
"sync_type": "StateSync",
"target_relay": "relay-2",
"status": "success",
"duration": 45,
"message_id": "msg-123",
"payload_size": 1024,
"latency": 45.2
},
{
"timestamp": 1703001570,
"sync_type": "HealthSync",
"target_relay": "relay-3",
"status": "success",
"duration": 32,
"message_id": "msg-122",
"payload_size": 512,
"latency": 32.1
}
],
"total": 2,
"successful": 2,
"failed": 0,
"filters": {
"limit": 10,
"since": 1703000000,
"sync_type": "StateSync"
},
"timestamp": 1703001600
}
```
### 9. Informations Bitcoin
**Flux :**
```
Client → GET /bitcoin/info → sdk_relay
sdk_relay → Bitcoin Info Response → Client
```
**Requête :**
```http
GET /bitcoin/info HTTP/1.1
Host: localhost:8091
User-Agent: curl/7.68.0
Accept: application/json
```
**Réponse :**
```json
{
"blockchain_info": {
"chain": "signet",
"blocks": 12345,
"headers": 12345,
"bestblockhash": "abc123def456789abcdef456789abcdef456789abc",
"difficulty": 1.0,
"verificationprogress": 0.9999,
"initialblockdownload": false,
"size_on_disk": 1073741824,
"pruned": false
},
"network_info": {
"connections": 8,
"connections_in": 4,
"connections_out": 4,
"networkactive": true,
"networks": [
{
"name": "ipv4",
"limited": false,
"reachable": true,
"proxy": "tor:9050"
}
]
},
"mempool_info": {
"size": 150,
"bytes": 1024000,
"usage": 2048000,
"maxmempool": 300000000,
"mempoolminfee": 0.00001000
},
"timestamp": 1703001600
}
```
### 10. Bloc Spécifique
**Flux :**
```
Client → GET /bitcoin/blocks/{block_hash} → sdk_relay
sdk_relay → Block Details Response → Client
```
**Requête :**
```http
GET /bitcoin/blocks/abc123def456789abcdef456789abcdef456789abc HTTP/1.1
Host: localhost:8091
User-Agent: curl/7.68.0
Accept: application/json
```
**Réponse :**
```json
{
"hash": "abc123def456789abcdef456789abcdef456789abc",
"height": 12345,
"version": 536870912,
"merkleroot": "def456789abcdef456789abcdef456789abcdef456",
"time": 1703001600,
"mediantime": 1703001500,
"nonce": 123456,
"bits": "207fffff",
"difficulty": 1.0,
"size": 1024,
"strippedsize": 512,
"weight": 4096,
"tx": [
"txid1abc123def456789abcdef456789abcdef456789abc",
"txid2def456789abcdef456789abcdef456789abcdef456"
],
"confirmations": 1,
"previousblockhash": "ghi789jkl012345ghi789jkl012345ghi789jkl012",
"nextblockhash": "mno012pqr345678mno012pqr345678mno012pqr345",
"timestamp": 1703001600
}
```
### 11. Logs
**Flux :**
```
Client → GET /logs → sdk_relay
sdk_relay → Logs Response → Client
```
**Requête :**
```http
GET /logs?level=info&limit=50&search=sync HTTP/1.1
Host: localhost:8091
User-Agent: curl/7.68.0
Accept: application/json
```
**Réponse :**
```json
{
"logs": [
{
"timestamp": "2024-12-19T10:00:00Z",
"level": "info",
"message": "Relay started successfully",
"relay_id": "relay-1",
"module": "main",
"line": 45
},
{
"timestamp": "2024-12-19T10:00:30Z",
"level": "info",
"message": "Sync completed",
"relay_id": "relay-1",
"sync_type": "StateSync",
"module": "sync",
"line": 123
}
],
"total": 2,
"levels": {
"debug": 0,
"info": 2,
"warn": 0,
"error": 0
},
"filters": {
"level": "info",
"limit": 50,
"search": "sync"
},
"timestamp": 1703001600
}
```
### 12. Mettre à Jour la Configuration
**Flux :**
```
Client → PUT /config → sdk_relay
sdk_relay → Config Update Response → Client
```
**Requête :**
```http
PUT /config HTTP/1.1
Host: localhost:8091
User-Agent: curl/7.68.0
Content-Type: application/json
Accept: application/json
```
**Réponse :**
```json
{
"status": "updated",
"changes": [
"sync.interval: 30 -> 60",
"sync.health_interval: 60 -> 120",
"dev_mode: true -> false"
],
"timestamp": 1703001600,
"restart_required": false
}
```
### 13. Redémarrer le Service
**Flux :**
```
Client → POST /restart → sdk_relay
sdk_relay → Restart Response → Client
```
**Requête :**
```http
POST /restart HTTP/1.1
Host: localhost:8091
User-Agent: curl/7.68.0
Accept: application/json
```
**Réponse :**
```json
{
"status": "restarting",
"timestamp": 1703001600,
"estimated_duration": "30s",
"restart_id": "restart-456"
}
```
---
## Codes d'Erreur
### WebSocket
- `1000` : Fermeture normale
- `1001` : Client part
- `1002` : Erreur de protocole
- `1003` : Type de données non supporté
- `1006` : Connexion fermée anormalement
- `1011` : Erreur serveur
### HTTP
- `200` : Succès
- `400` : Requête invalide
- `401` : Non autorisé
- `404` : Endpoint non trouvé
- `422` : Données invalides
- `429` : Trop de requêtes
- `500` : Erreur serveur interne
- `503` : Service indisponible
---
## Exemples d'Utilisation
### Client JavaScript
```javascript
class SdkRelayClient {
constructor(wsUrl, httpUrl) {
this.wsUrl = wsUrl;
this.httpUrl = httpUrl;
this.ws = null;
this.clientId = `client-${Date.now()}`;
}
async connect() {
return new Promise((resolve, reject) => {
this.ws = new WebSocket(this.wsUrl);
this.ws.onopen = () => {
console.log('Connecté à sdk_relay');
this.sendHandshake();
resolve();
};
this.ws.onmessage = (event) => {
const message = JSON.parse(event.data);
this.handleMessage(message);
};
this.ws.onerror = (error) => {
console.error('Erreur WebSocket:', error);
reject(error);
};
});
}
sendHandshake() {
const handshake = {
type: 'handshake',
client_id: this.clientId,
version: '1.0.0',
capabilities: ['sync', 'notifications', 'health']
};
this.ws.send(JSON.stringify(handshake));
}
handleMessage(message) {
switch(message.type) {
case 'handshake_response':
console.log('Handshake accepté');
break;
case 'notification':
this.handleNotification(message);
break;
case 'sync':
this.handleSync(message);
break;
case 'pong':
console.log('Pong reçu');
break;
}
}
handleNotification(message) {
console.log('Notification:', message.notification_type, message.data);
}
handleSync(message) {
console.log('Sync:', message.sync_type, message.payload);
}
// Méthodes HTTP
async getHealth() {
const response = await fetch(`${this.httpUrl}/health`);
return response.json();
}
async getMetrics() {
const response = await fetch(`${this.httpUrl}/metrics`);
return response.json();
}
async getRelays() {
const response = await fetch(`${this.httpUrl}/relays`);
return response.json();
}
async forceSync(syncTypes = ['StateSync']) {
const response = await fetch(`${this.httpUrl}/sync/force`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ sync_types: syncTypes })
});
return response.json();
}
disconnect() {
if (this.ws) {
this.ws.close();
}
}
}
// Utilisation
const client = new SdkRelayClient('ws://localhost:8090', 'http://localhost:8091');
async function main() {
await client.connect();
// Obtenir les métriques
const metrics = await client.getMetrics();
console.log('Métriques:', metrics);
// Forcer une synchronisation
await client.forceSync(['HealthSync']);
}
main().catch(console.error);
```
### Client Python
```python
import asyncio
import aiohttp
import json
import websockets
from datetime import datetime
class SdkRelayClient:
def __init__(self, ws_url, http_url):
self.ws_url = ws_url
self.http_url = http_url
self.websocket = None
self.client_id = f"python-client-{int(datetime.now().timestamp())}"
async def connect(self):
self.websocket = await websockets.connect(self.ws_url)
await self.send_handshake()
async def send_handshake(self):
handshake = {
"type": "handshake",
"client_id": self.client_id,
"version": "1.0.0",
"capabilities": ["sync", "notifications", "health"]
}
await self.websocket.send(json.dumps(handshake))
async def listen(self):
async for message in self.websocket:
data = json.loads(message)
await self.handle_message(data)
async def handle_message(self, message):
if message['type'] == 'handshake_response':
print(f"Handshake accepté par {message['relay_id']}")
elif message['type'] == 'notification':
await self.handle_notification(message)
elif message['type'] == 'sync':
await self.handle_sync(message)
async def handle_notification(self, message):
print(f"Notification {message['notification_type']}: {message['data']}")
async def handle_sync(self, message):
print(f"Sync {message['sync_type']}: {message['payload']}")
# Méthodes HTTP
async def get_health(self):
async with aiohttp.ClientSession() as session:
async with session.get(f"{self.http_url}/health") as response:
return await response.json()
async def get_metrics(self):
async with aiohttp.ClientSession() as session:
async with session.get(f"{self.http_url}/metrics") as response:
return await response.json()
async def get_relays(self):
async with aiohttp.ClientSession() as session:
async with session.get(f"{self.http_url}/relays") as response:
return await response.json()
async def force_sync(self, sync_types=None):
if sync_types is None:
sync_types = ['StateSync']
async with aiohttp.ClientSession() as session:
async with session.post(
f"{self.http_url}/sync/force",
json={"sync_types": sync_types}
) as response:
return await response.json()
async def close(self):
if self.websocket:
await self.websocket.close()
async def main():
client = SdkRelayClient('ws://localhost:8090', 'http://localhost:8091')
try:
await client.connect()
# Obtenir les métriques
metrics = await client.get_metrics()
print("Métriques:", metrics)
# Écouter les messages
await client.listen()
except Exception as e:
print(f"Erreur: {e}")
finally:
await client.close()
if __name__ == "__main__":
asyncio.run(main())
```
### Client cURL
```bash
# Vérifier la santé
curl -X GET http://localhost:8091/health
# Obtenir les métriques
curl -X GET http://localhost:8091/metrics
# Obtenir la liste des relais
curl -X GET http://localhost:8091/relays
# Obtenir les détails d'un relais
curl -X GET http://localhost:8091/relays/relay-1
# Forcer une synchronisation
curl -X POST http://localhost:8091/sync/force \
-H "Content-Type: application/json" \
-d '{"sync_types": ["StateSync", "HealthSync"]}'
# Obtenir l'historique des synchronisations
curl -X GET "http://localhost:8091/sync/history?limit=10"
# Obtenir les logs
curl -X GET "http://localhost:8091/logs?level=info&limit=50"
# Obtenir les informations Bitcoin
curl -X GET http://localhost:8091/bitcoin/info
# Obtenir un bloc spécifique
curl -X GET http://localhost:8091/bitcoin/blocks/abc123...
# Mettre à jour la configuration
curl -X PUT http://localhost:8091/config \
-H "Content-Type: application/json" \
-d '{"sync": {"interval": 60}}'
# Redémarrer le service
curl -X POST http://localhost:8091/restart
```
---
**Cette documentation décrit tous les flux de données JSON entre les clients et sdk_relay.** 🚀