Clore.ai bietet eine REST-API die vollständigen programmgesteuerten Zugriff auf den GPU-Marktplatz ermöglicht — Auflisten von Servern, Erstellen von Bestellungen, Überwachen von Deployments und Stornieren von Vermietungen.
Hinweis: Es gibt derzeit kein offizielles CLI-Binary. Alle Automatisierungen erfolgen direkt über die REST-API mit Tools wie curl, Python oder Node.js.
Basis-URL:https://api.clore.ai/v1
Antwortformat: JSON. Jede Antwort enthält ein code Feld, das den Status angibt.
Spot-Bestellungen sind günstiger, können aber überboten werden. Sie legen Ihren Preis pro Tag fest:
Bestellstatus prüfen
Aktive Bestellungen enthalten pub_cluster (Hostnamen) und tcp_ports für SSH-Zugriff:
SSH auf Ihren gemieteten Server:
Eine Bestellung stornieren
Optional können Sie ein Problem mit dem Server melden:
Python SDK
Ein leichter Wrapper, der die requests Bibliothek verwendet. Installieren Sie sie mit:
CloreClient-Klasse
Vollständiges funktionierendes Beispiel
Node.js-Beispiel
Verwendung der nativen fetch API (Node.js 18+):
Gängige Workflows
Günstigste RTX 4090 finden und mieten
Meine Bestellungen überwachen
Automatisch mieten, wenn der Preis unter X fällt
WebSocket
Die Clore.ai REST-API bietet derzeit keinen WebSocket-Endpunkt. Für Echtzeitüberwachung verwenden Sie Polling mit einem angemessenen Intervall (siehe Ratenbegrenzungen unten).
Ratenbegrenzungen
Endpunkt
Limit
Die meisten Endpunkte
1 Anfrage/Sekunde
create_order
1 Anfrage/5 Sekunden
set_spot_price (Preissenkung)
Einmal pro 600 Sekunden
Antwort bei Erreichen des Ratenlimits (Code 5):
Best Practices:
Fügen Sie hinzu time.sleep(1) zwischen aufeinanderfolgenden API-Aufrufen
Für create_order, warten Sie mindestens 5 Sekunden zwischen Anfragen
Verwenden Sie Polling-Intervalle von 60+ Sekunden für Überwachungs-Schleifen
Cachen Sie Marktplatzdaten lokal, wenn Sie sie häufig abfragen müssen
Python-Helfer:
Fehlerbehandlung
Jede API-Antwort enthält ein code Feld. Ein Wert von 0 bedeutet Erfolg.
Fehlercodes
Code
Bedeutung
Aktion
0
Erfolg
—
1
Datenbankfehler
Nach einer Verzögerung erneut versuchen
2
Ungültige Eingabedaten
Überprüfen Sie Ihren Anfragekörper/Parameter
3
Ungültiges API-Token
Überprüfen Sie Ihren API-Schlüssel im Dashboard
4
Ungültiger Endpunkt
Überprüfen Sie die Endpunkt-URL
5
Ratenlimit überschritten (1 req/sec)
Fügen Sie Verzögerungen zwischen Anfragen hinzu
6
Anwendungsfehler (siehe Fehler Feld)
Lesen Sie das Fehler Feld für Details
Code 6 Unterfehler
Fehler Wert
Bedeutung
exceeded_max_step
Spot-Preisreduzierung zu groß; überprüfen Sie max_step Feld
can_lower_every_600_seconds
Muss warten, bevor der Spot-Preis erneut gesenkt werden kann; überprüfen Sie time_to_lowering
Python Fehlerbeispiel zur Fehlerbehandlung
JavaScript Fehlerbeispiel zur Fehlerbehandlung
Verfügbare Docker-Images
Clore.ai stellt vorgefertigte Images bereit, die für GPU-Workloads optimiert sind:
Image
Beschreibung
cloreai/ubuntu20.04-jupyter
Ubuntu 20.04 + JupyterLab
cloreai/ubuntu22.04-jupyter
Ubuntu 22.04 + JupyterLab
Sie können auch jedes öffentliche Docker Hub-Image verwenden. Für GPU-Zugriff verwenden Sie CUDA-fähige Images, z. B.:
Portweiterleitung
Geben Sie beim Erstellen einer Bestellung Ports an, die expose werden sollen:
"tcp" — Direkte TCP-Portweiterleitung (für SSH, benutzerdefinierte Server)
"http" — HTTPS-Proxy (für Jupyter, Web-UIs). Es ist nur ein HTTP-Port pro http_port Feld erlaubt.
Nach Erstellung der Bestellung erscheinen Verbindungsdetails in my_orders:
Verbinden über SSH:
Zugriff auf Jupyter über den Browser: https://n1.c1.clorecloud.net (verwendet das http_port)
from clore_client import CloreClient
client = CloreClient(api_key="YOUR_API_KEY")
def rent_cheapest_rtx4090(image="cloreai/ubuntu20.04-jupyter", ssh_password="SecurePass123"):
servers = client.list_servers()
# Filter: verfügbare RTX 4090
candidates = [
s for s in servers
if "4090" in s["specs"].get("gpu", "")
and not s["rented"]
]
if not candidates:
raise RuntimeError("Keine verfügbaren RTX 4090-Server gefunden")
# Nach On-Demand-BTC-Preis sortieren
candidates.sort(key=lambda s: s["price"]["on_demand"]["bitcoin"])
best = candidates[0]
price_btc = best["price"]["on_demand"]["bitcoin"]
print(f"Miete Server {best['id']}: {best['specs']['gpu']} @ {price_btc:.8f} BTC/Tag")
client.create_order(
server_id=best["id"],
image=image,
order_type="on-demand",
currency="bitcoin",
ports={"22": "tcp"},
ssh_password=ssh_password,
)
print("Fertig! Überprüfen Sie Ihre Bestellungen für SSH-Verbindungsdaten.")
return best["id"]
rent_cheapest_rtx4090()
import time
from clore_client import CloreClient
client = CloreClient(api_key="YOUR_API_KEY")
def monitor_orders(poll_interval_seconds=60):
"""Bestellungen abfragen und Statusaktualisierungen ausgeben."""
print(f"Überwache Bestellungen (Abfrage alle {poll_interval_seconds}s). Strg+C zum Beenden.\n")
while True:
orders = client.get_orders(include_completed=False)
active = [o for o in orders if not o.get("expired")]
print(f"--- {len(active)} aktive Bestellung(en) ---")
for order in active:
cluster = order.get("pub_cluster", [])
tcp = order.get("tcp_ports", [])
spend = order.get("spend", 0)
ssh_info = ""
if cluster and tcp:
port = tcp[0].split(":")[1]
ssh_info = f" | SSH: {cluster[0]}:{port}"
print(f" Bestellung {order['id']}: Server {order['si']}"
f" | ausgegeben {spend:.8f} BTC{ssh_info}")
if not active:
print(" Keine aktiven Bestellungen.")
print()
time.sleep(poll_interval_seconds)
monitor_orders()
import time
from clore_client import CloreClient
client = CloreClient(api_key="YOUR_API_KEY")
def auto_rent_on_price_drop(
gpu_model: str = "RTX 4090",
max_price_btc: float = 0.00015,
image: str = "cloreai/ubuntu20.04-jupyter",
ssh_password: str = "SecurePass123",
check_interval_seconds: int = 120,
):
"""
Beobachten Sie den Marktplatz und mieten Sie automatisch eine GPU, wenn der Preis unter die Schwelle fällt.
Parameter:
gpu_model: GPU-Name, nach dem gesucht wird (case-insensitive)
max_price_btc: Maximal akzeptabler Preis pro Tag in BTC
image: Docker-Image, das bereitgestellt werden soll
ssh_password: SSH-Passwort für den Container
check_interval_seconds: Wie oft geprüft wird (beachten Sie die Rate-Limits!)
"""
print(f"Suche nach {gpu_model} bei ≤ {max_price_btc:.8f} BTC/Tag...")
while True:
servers = client.list_servers()
for server in servers:
gpu = server["specs"].get("gpu", "")
if gpu_model.lower() not in gpu.lower():
continue
if server["rented"]:
continue
price = server["price"]["on_demand"]["bitcoin"]
if price <= max_price_btc:
print(f"🎯 Treffer gefunden! Server {server['id']}: {gpu} @ {price:.8f} BTC/Tag")
try:
client.create_order(
server_id=server["id"],
image=image,
order_type="on-demand",
currency="bitcoin",
ports={"22": "tcp"},
ssh_password=ssh_password,
required_price=price, # Diesen Preis sperren
)
print(f"✅ Bestellung für Server {server['id']} erstellt!")
return server["id"]
except Exception as e:
print(f"Failed to create order: {e}. Will retry...")
print(f"No match yet. Checking again in {check_interval_seconds}s...")
time.sleep(check_interval_seconds)
auto_rent_on_price_drop(gpu_model="4090", max_price_btc=0.00012)
{ "code": 5 }
import time
def safe_api_call(fn, *args, delay=1.1, **kwargs):
"""Wickelt einen API-Aufruf mit Ratenlimit-Sicherheit ein."""
result = fn(*args, **kwargs)
time.sleep(delay)
return result
from clore_client import CloreClient, CloreAPIError
import time
client = CloreClient(api_key="YOUR_API_KEY")
def create_order_with_retry(server_id, image, max_retries=3):
for attempt in range(max_retries):
try:
return client.create_order(
server_id=server_id,
image=image,
order_type="on-demand",
currency="bitcoin",
ports={"22": "tcp"},
ssh_password="SecurePass123",
)
except CloreAPIError as e:
if e.code == 5: # Ratenlimit
print(f"Rate limited. Waiting 5s... (attempt {attempt+1}/{max_retries})")
time.sleep(5)
elif e.code == 3: # Ungültiger API-Schlüssel
print("Ungültiger API-Schlüssel! Überprüfen Sie Ihren CLORE_API_KEY.")
raise
elif e.code == 2: # Ungültige Eingabe
print(f"Invalid request: {e}")
raise
else:
print(f"API error: {e}. Retrying in 3s...")
time.sleep(3)
raise RuntimeError(f"Failed after {max_retries} attempts")
async function createOrderWithRetry(client, serverConfig, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await client.createOrder(serverConfig);
} catch (err) {
const code = parseInt(err.message.match(/error (\d+)/)?.[1]);
if (code === 5) {
console.log(`Rate limited. Waiting 5s... (attempt ${attempt + 1}/${maxRetries})`);
await new Promise(r => setTimeout(r, 5000));
} else if (code === 3) {
throw new Error('Invalid API key');
} else {
console.log(`API error: ${err.message}. Retrying in 3s...`);
await new Promise(r => setTimeout(r, 3000));
}
}
}
throw new Error(`Failed after ${maxRetries} attempts`);
}