Store Cloud · Entwickler-Dokumentation
Dateien speichern mit deinem persönlichen API-Key
Die AllGPT AI Store Cloud ist ein einfacher Objektspeicher für deine Apps: Du lädst Dateien (Bilder, JSON, Modelle, Backups …) über eine HTTP-API hoch, lädst sie herunter, ersetzt oder löschst sie – abgesichert durch einen persönlichen API-Key. Jeder Entwickler bekommt 512 MB. Mit Multimode desselben Keys zusätzlich Räume, Live-Events und Ranglisten für Mehrspieler. Verwaltet wird alles in der Cloud-Oberfläche.
1 · Überblick
Du brauchst keinen SDK und keine Bibliothek – die Cloud ist reines HTTP. Vier Bausteine:
- Persönlicher API-Key – startet mit
agc_, wird bei dir nur als Hash gespeichert. Er ist wie ein Passwort zu behandeln. - Dateien – liegen in deinem privaten Bereich, adressiert über einen Pfad wie
assets/icon.png. Ordner entstehen automatisch. - Quota – 512 MB pro Entwickler, einzelne Dateien bis 128 MB.
- Logs – jeder Zugriff (Erfolg und Ablehnung) wird 30 Tage protokolliert und ist in der Oberfläche sichtbar.
PUT https://allgpt.org/cloud/api/files/pfad mit Header Authorization: Bearer agc_… lädt hoch. GET auf denselben Pfad lädt herunter.Deine Dateien liegen auf dedizierten Speicher-Laufwerken des Stores, nicht auf der Systemplatte. Die Cloud ist bewusst von den Store-Apps getrennt: ein WebApp-API-Key (Sandbox-Proxy) gilt nicht für die Cloud – und umgekehrt.
2 · Wer kann die Cloud nutzen?
Nur Entwickler mit genehmigtem Store-Namen. Das ist derselbe Status, mit dem du Apps im Studio veröffentlichst:
- Konto erstellen – auf der Store-Seite über „Login → Registrieren".
- Bewerbung einreichen – im Konto-Bereich deinen Store-Namen beantragen (APK optional).
- Freigabe abwarten – nach der Genehmigung des Admins schaltet sich die Cloud automatisch frei.
- Cloud öffnen – allgpt.org/cloud (auch im Studio unter „Store Cloud").
Nicht freigegebene Konten sehen in der Cloud-Oberfläche nur einen Hinweis auf die Bewerbung. Der API-Zugriff ist dann ebenfalls gesperrt.
3 · API-Key erstellen
- Öffne die Cloud und melde dich an.
- Wechsle zum Reiter API-Keys.
- Gib dem Schlüssel einen Namen (z. B. „Produktions-Server") und klicke Neuen Schlüssel erstellen.
- Der vollständige Schlüssel (
agc_…) erscheint einmalig in einem Dialog. Kopiere ihn sofort in deinen Passwort-Manager oder eine Secret-Store-Variable.
Du kannst bis zu fünf Schlüssel parallel haben – sinnvoll getrennt nach Umgebung (z. B. je einer für Entwicklung, Produktion und ein CI-Job). Jeder Schlüssel widerrufen jederzeit per „Widerrufen".
4 · Authentifizierung
Jeder API-Aufruf trägt deinen Schlüssel als Bearer-Token im Header:
Authorization: Bearer agc_DEIN_SCHLUESSEL
Der Schlüssel ist an dein Konto gebunden – du siegst und änderst nur deine eigenen Dateien. Ein falscher, widerrufener oder fehlender Schlüssel führt zu 401. Es gibt keine Cookies und keinen Login für die API; der Header ist die einzige Anmeldung. Deshalb funktioniert die API auch serverseitig aus jeder Sprache.
5 · Die API-Referenz
Alle Endpunkte beginnen mit https://allgpt.org/cloud/api. Antworten sind JSON, außer beim Datei-Download (dann die Datei selbst).
Key & Konto
| Methode & Pfad | Zweck |
|---|---|
GET /me | Dein Konto, belegter Speicher, Dateianzahl und deine Keys (nur Vorschau). |
GET /list?prefix=assets | Dateien auflisten, optional nur unter einem Präfix/Ordner. |
GET /logs?limit=100 | Deine letzten Ereignisse (max. 500). |
Dateien
| Methode & Pfad | Zweck |
|---|---|
PUT /files/<pfad> | Kleine Datei direkt hochladen (Body = Bytes, bis 16 MB). Ersetzt eine bestehende Datei am selben Pfad. |
GET /files/<pfad> | Datei herunterladen. Bilder/Audio/Video/Text inline, alles andere als Download. |
DELETE /files/<pfad> | Datei löschen. |
Chunk-Upload (für Dateien über 16 MB)
| Methode & Pfad | Zweck |
|---|---|
POST /uploads | Start. JSON {"path":"…","size":12345} → Antwort {"id","chunkSize"}. |
PUT /uploads/<id>?offset=N | Ein Chunk (Roh-Bytes) an Position N senden. Antwort {"received"}. |
POST /uploads/<id>/complete | Upload abschließen und Datei einreihen. |
DELETE /uploads/<id> | Abbrechen und Platz freigeben. |
chunkSize ist 8 MB. Sende Chunks nacheinander bei offset=0 beginnend; der nächste Offset ist immer das gemeldete received. Abgeschlossene, aber nie vollendete Uploads räumt der Store nach 24 h automatisch auf.
Pfadregeln
- Normaler Pfad wie
report/2026/q3.pdf; Ordner werden beim Hochladen automatisch angelegt. - Erlaubt sind Buchstaben, Zahlen,
. _ - ( ) [ ]und Leerzeichen in den Namen. Maximal 16 Ebenen, 512 Zeichen. .., führende Schrägstriche und versteckte Systempfade sind gesperrt – du kannst nie aus deinem Bereich ausbrechen.- Pfade sind case-insensitive eindeutig:
Logo.pngundlogo.pngsind dieselbe Datei.
6 · Beispiele einbauen
Ersetze agc_DEIN_SCHLUESSEL durch deinen echten Key – am besten über eine Umgebungsvariable, nie im Quelltext.
curl – schnell testen
# kleine Datei hochladen
curl -X PUT https://allgpt.org/cloud/api/files/config/settings.json \
-H "Authorization: Bearer $AGC_KEY" \
--data-binary @settings.json
# Dateien auflisten
curl https://allgpt.org/cloud/api/list \
-H "Authorization: Bearer $AGC_KEY"
# herunterladen / löschen
curl -O -J https://allgpt.org/cloud/api/files/config/settings.json -H "Authorization: Bearer $AGC_KEY"
curl -X DELETE https://allgpt.org/cloud/api/files/config/settings.json -H "Authorization: Bearer $AGC_KEY"
JavaScript (Node, Server-Build, Skript)
const KEY = process.env.AGC_KEY; // nie hart codieren
const BASE = "https://allgpt.org/cloud/api";
// hochladen (klein: direkt)
async function put(path, data) {
const r = await fetch(`${BASE}/files/${path}`, {
method: "PUT",
headers: { Authorization: `Bearer ${KEY}` },
body: data, // string | Buffer | Blob | ArrayBuffer
});
if (!r.ok) throw new Error((await r.json()).error);
return r.json(); // { ok, path, size, replaced }
}
// große Datei mit Chunk-Upload
async function putBig(path, buffer, chunkSize = 8 * 1024 * 1024) {
const { id } = await (await fetch(`${BASE}/uploads`, {
method: "POST",
headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ path, size: buffer.length }),
})).json();
for (let off = 0; off < buffer.length; off += chunkSize) {
const chunk = buffer.subarray(off, off + chunkSize);
await fetch(`${BASE}/uploads/${id}?offset=${off}`, {
method: "PUT", headers: { Authorization: `Bearer ${KEY}` }, body: chunk,
});
}
return (await fetch(`${BASE}/uploads/${id}/complete`, {
method: "POST", headers: { Authorization: `Bearer ${KEY}` },
})).json();
}
const data = await (await fetch(`${BASE}/files/report.json`, {
headers: { Authorization: `Bearer ${KEY}` },
})).json();
Python (requests)
import os, requests
KEY = os.environ["AGC_KEY"]
BASE = "https://allgpt.org/cloud/api"
H = {"Authorization": f"Bearer {KEY}"}
# klein direkt
requests.put(f"{BASE}/files/note.txt", data="Hallo Cloud".encode(), headers=H).raise_for_status()
# groß im Chunk
def put_big(path, raw, chunk=8 * 1024 * 1024):
up = requests.post(f"{BASE}/uploads", json={"path": path, "size": len(raw)}, headers=H).json()
for off in range(0, len(raw), chunk):
requests.put(f"{BASE}/uploads/{up['id']}?offset={off}", data=raw[off:off+chunk], headers=H).raise_for_status()
requests.post(f"{BASE}/uploads/{up['id']}/complete", headers=H).raise_for_status()
files = requests.get(f"{BASE}/list", headers=H).json()["files"]
body = requests.get(f"{BASE}/files/note.txt", headers=H).text
requests.delete(f"{BASE}/files/note.txt", headers=H)
In einer Store-WebApp?
Eine WebApp läuft im Browser und darf deinen Cloud-Key nicht sehen. Für Echtzeit- und Mehrspieler-Funktionen in deiner WebApp gibt es deshalb Multimode: Deine WebApp tritt Räumen mit einem Raum-Token (mmr_…) bei, das nie deinen Key verrät – und Ranglisten sind sogar ohne Token lesbar. Für den reinen Dateispeicher gilt weiter: Baust du einen eigenen Backend-Dienst, hält der den Key und gibt Daten per HTTPS an die WebApp weiter.
7 · Multimode – Mehrspieler ohne eigene Server-API
Multimode baut auf derselben Cloud auf und braucht denselben persönlichen API-Key – du brauchst keinen zweiten Account und keine neue Anmeldung. Es liefert die Echtzeit-Bausteine, die Mehrspieler-Spiele und Kollaborations-Apps immer brauchen:
- Räume (
rooms) – ein Ort, an dem Spieler zusammenkommen: beitreten, wieder gehen, sehen wer online ist. - Events – Broadcast-Nachrichten an alle im Raum (Züge, Kugeln, Chat, ready), mit lückenloser Sequenznummer.
- Geteilter Zustand (
state) – ein kleines JSON pro Raum (z. B. das Spielbrett) mit Versionsprüfung gegen Überschreiben. - Ranglisten (
boards) – server-authoritative Bestenlisten, die nur dein Backend mit dem API-Key schreibt.
agc_…-Key über /cloud/api/mm/…. Spieler, Browser und WebApps treten mit einem Raum-Token (mmr_…) bei – es gilt genau für einen Raum und kann nie deinen API-Key oder deine Dateien lesen.Ablauf
- Raum anlegen –
POST /cloud/api/mm/roomsmit deinem Key (Name, Kapazität, optional Passwort). - Token erzeugen –
POST /cloud/api/mm/rooms/<raum>/tokens. Du gibst dasmmr_…-Token an deine Clients weiter (z. B. eingebettet in deine WebApp oder nach einem Login bei dir). - Beitreten –
POST …/joinmit Token + Spielername. Antwort: Session-Token (HeaderX-MM-Session) + alle aktiven Spieler. - Spielen –
POST …/eventssenden, neue Ereignisse perGET …/events?after=SEQabholen oder perGET …/streamals Server-Sent-Events live empfangen.POST …/pinghält dich online (Presence 60 s).
Räume
| Methode & Pfad | Zweck |
|---|---|
POST /mm/rooms | Raum anlegen. JSON {"name":"lobby-1","capacity":8,"kind":"public|private","password":"…","meta":{…}}. |
GET /mm/rooms | Deine Räume mit Online-Zahl (Key). |
GET·PATCH·DELETE /mm/rooms/<name> | Einzelnen Raum lesen, ändern (Kapazität, Passwort, Meta) oder löschen (Key). |
POST·GET /mm/rooms/<name>/tokens | Beitritts-Tokens erzeugen (JSON {"label","ttl"}, bis 30 Tage) / auflisten. Token-Wert erscheint nur einmal. |
DELETE /mm/tokens/<id> | Token widerrufen –Clients fliegen sofort raus (Key). |
Im Raum (Key oder Raum-Token)
| Methode & Pfad | Zweck |
|---|---|
POST /mm/rooms/<name>/join | Beitreten: {"player":"anna","password":"…","data":{…}}. Antwort: Session + Spielerliste. Gleichnamiges Re-Join ersetzt die Session. |
POST …/leave · …/ping · …/ready | Verlassen · Präsenz auffrischen (alle ~30 s) · Bereit-Signal. |
GET · POST …/events | POST sendet {"type":"move","data":{…}} an alle (max. 8 KB, Absender = deine Session). GET holt alles nach ?after=SEQ (Polling). |
GET …/stream | Server-Sent-Events: live, hält bis 60 s, dann neu verbinden (browser-üblich). Token per ?access_token=, da EventSource keine Header setzen kann. |
GET · POST …/state | Geteilter Zustand (max. 32 KB JSON). POST mit rev prüft die Version → 409 bei Konflikt; optional "broadcast":false. |
GET …/snapshot | Alles auf einmal: Spieler, Zustand, letztere Event-Sequenz. |
Ranglisten (nur Key – Scores sollen fälschungssicher sein)
| Methode & Pfad | Zweck |
|---|---|
POST · GET /mm/boards | Rangliste anlegen ({"name":"highscore"}) / alle deine listen. Namen sind global eindeutig, weil die Score-Liste ohne Key lesbar ist. |
DELETE /mm/boards/<name> | Rangliste löschen. |
PUT /mm/boards/<name>/scores/<spieler> | Score setzen: {"score":300,"mode":"set|max|min","data":{…}}. max verbessert nur nach oben. |
GET /mm/boards/<name>/scores?limit=50 | Top-Liste mit Rängen – ohne Key lesbar, für deine Lobby-WebApp also gefahrlos. |
DELETE /mm/boards/<name>/scores/<spieler> | Einen Eintrag entfernen. |
Beispiel: zwei Browser schlagen sich die Bälle zu
// —— Deine Server-Funktion (hält den agc_-Key, läuft z. B. in deinem Backend):
async function createRoom(name) {
const H = { Authorization: `Bearer ${process.env.AGC_KEY}`, "Content-Type": "application/json" };
await fetch("https://allgpt.org/cloud/api/mm/rooms", {
method: "POST", headers: H, body: JSON.stringify({ name, capacity: 2 }),
});
const { token } = await (await fetch(`https://allgpt.org/cloud/api/mm/rooms/${name}/tokens`, {
method: "POST", headers: H, body: JSON.stringify({ label: "spiel", ttl: 3600 }),
})).json();
return token; // mmr_… – diesen Token bekommst du als Spieler, nie den agc_-Key
}
// —— Im Browser deiner WebApp (nur mit mmr_-Token):
const BASE = "https://allgpt.org/cloud/api";
const H = { Authorization: `Bearer ${ROOM_TOKEN}`, "Content-Type": "application/json" };
const me = await (await fetch(`${BASE}/mm/rooms/${ROOM}/join`, {
method: "POST", headers: H, body: JSON.stringify({ player: "Anna" }),
})).json();
H["X-MM-Session"] = me.session;
// hereingekommene Züge live anzeigen (EventSource verbindet sich selbst neu):
const stream = new EventSource(`${BASE}/mm/rooms/${ROOM}/stream?access_token=${ROOM_TOKEN}`);
stream.addEventListener("zug", (e) => anzeigen(JSON.parse(e.data).data));
// eigenen Zug an den Gegner senden:
await fetch(`${BASE}/mm/rooms/${ROOM}/events`, {
method: "POST", headers: H, body: JSON.stringify({ type: "zug", data: { feld: "d4" } }),
});
// Rangliste anzeigen – geht sogar ohne jeden Token:
const top = await (await fetch(`${BASE}/mm/boards/highscore/scores`)).json();
Grenzen pro Entwickler: 50 Räume (je max. 32 Spieler), 10 Tokens pro Raum, 20 Ranglisten (je 500 Einträge), Events die letzten 500 pro Raum, 120 Multimode-Anfragen/min. Presence erlischt nach 60 s ohne ping. Multimode belastet deine 512-MB-Datei-Quota nicht – es läuft über die Store-Datenbank, nicht das Cloud-Laufwerk.
8 · Grenzen & Fair Use
| Was | Grenze |
|---|---|
| Speicher pro Entwickler | 512 MB (alle Dateien zusammen) |
| Einzelne Datei | 128 MB |
| Direkter Upload (PUT ohne Chunks) | 16 MB |
| API-Keys pro Entwickler | 5 |
| Anfragen | 300 pro Minute (danach 429); Multimode separat: 120 pro Minute |
| Ordner-Ebenen pro Pfad | 16 |
| Multimode | 50 Räume · 32 Spieler/Raum · 10 Tokens/Raum · 20 Ranglisten · 500 Events/Raum |
| Log-Aufbewahrung | 30 Tage |
Die Cloud ist ein Speicher für deine App-Dateien, kein öffentlicher Datei-Host und kein Backup-Dienst für Dritte. Inhalte müssen den Store-Regeln entsprechen. Der Admin kann bei Missbrauch einzelne Keys oder Konten sperren.
9 · Häufige Fehler
| Status | Bedeutung & Lösung |
|---|---|
401 | Kein oder falscher Authorization-Header. Schlüssel prüfen, nicht widerrufen? Sonst neu erstellen. |
403 | Konto nicht freigegeben. Bewerbung einreichen und Genehmigung abwarten. |
404 | Datei existiert nicht (Groß-/Kleinschreibung egal, Tippfehler nicht). |
409 | Chunk-Offset passt nicht, Raum voll, Name schon vergeben oder State-Revision veraltet. Mit dem gemeldeten Stand erneut versuchen. |
413 | Quota voll oder Datei > 128 MB. Ältere Dateien löschen bzw. kleiner machen. |
429 | Zu viele Anfragen. Drosseln und mit Verzögerung erneut versuchen. |
503 | Cloud-Laufwerk kurz nicht erreichbar (z. B. Stick wird gewartet). Später erneut versuchen. |
Tipp: Im Reiter Logs der Cloud-Oberfläche siehst du jede abgelehnte Anfrage mit Zeit und IP – der schnellste Weg, ein Problem einzugrenzen.
Zurück zur Cloud-Oberfläche · WebApp-Dokumentation · Fragen an den Admin über das Store-Kontaktformular.