AllGPT AI Store

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.
Kurz gesagt: 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:

  1. Konto erstellen – auf der Store-Seite über „Login → Registrieren".
  2. Bewerbung einreichen – im Konto-Bereich deinen Store-Namen beantragen (APK optional).
  3. Freigabe abwarten – nach der Genehmigung des Admins schaltet sich die Cloud automatisch frei.
  4. 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

  1. Öffne die Cloud und melde dich an.
  2. Wechsle zum Reiter API-Keys.
  3. Gib dem Schlüssel einen Namen (z. B. „Produktions-Server") und klicke Neuen Schlüssel erstellen.
  4. Der vollständige Schlüssel (agc_…) erscheint einmalig in einem Dialog. Kopiere ihn sofort in deinen Passwort-Manager oder eine Secret-Store-Variable.
Der Schlüssel wird nie wieder angezeigt. Der Store speichert nur einen Hash. In der Oberfläche siehst du später nur noch die letzten vier Zeichen. Wenn du ihn verlierst: Rotieren erzeugt einen neuen Wert (der alte wird sofort ungültig).

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.

Wichtig: Setze den Schlüssel niemals in Code, der im Browser deiner WebApp läuft. Für WebApps gibt es den getrennten Schlüssel-Proxy. Die Cloud-API ist für deine Server, Skripte und CI gedacht, die den Schlüssel sicher halten können.

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 & PfadZweck
GET /meDein Konto, belegter Speicher, Dateianzahl und deine Keys (nur Vorschau).
GET /list?prefix=assetsDateien auflisten, optional nur unter einem Präfix/Ordner.
GET /logs?limit=100Deine letzten Ereignisse (max. 500).

Dateien

Methode & PfadZweck
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 & PfadZweck
POST /uploadsStart. JSON {"path":"…","size":12345} → Antwort {"id","chunkSize"}.
PUT /uploads/<id>?offset=NEin Chunk (Roh-Bytes) an Position N senden. Antwort {"received"}.
POST /uploads/<id>/completeUpload 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.png und logo.png sind 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.
Ein Key für alles: Verwaltung (Räume anlegen, Tokens erzeugen, Ranglisten pflegen) läuft mit deinem bisherigen 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

  1. Raum anlegen – POST /cloud/api/mm/rooms mit deinem Key (Name, Kapazität, optional Passwort).
  2. Token erzeugen – POST /cloud/api/mm/rooms/<raum>/tokens. Du gibst das mmr_…-Token an deine Clients weiter (z. B. eingebettet in deine WebApp oder nach einem Login bei dir).
  3. Beitreten – POST …/join mit Token + Spielername. Antwort: Session-Token (Header X-MM-Session) + alle aktiven Spieler.
  4. Spielen – POST …/events senden, neue Ereignisse per GET …/events?after=SEQ abholen oder per GET …/stream als Server-Sent-Events live empfangen. POST …/ping hält dich online (Presence 60 s).

Räume

Methode & PfadZweck
POST /mm/roomsRaum anlegen. JSON {"name":"lobby-1","capacity":8,"kind":"public|private","password":"…","meta":{…}}.
GET /mm/roomsDeine 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>/tokensBeitritts-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 & PfadZweck
POST /mm/rooms/<name>/joinBeitreten: {"player":"anna","password":"…","data":{…}}. Antwort: Session + Spielerliste. Gleichnamiges Re-Join ersetzt die Session.
POST …/leave · …/ping · …/readyVerlassen · Präsenz auffrischen (alle ~30 s) · Bereit-Signal.
GET · POST …/eventsPOST sendet {"type":"move","data":{…}} an alle (max. 8 KB, Absender = deine Session). GET holt alles nach ?after=SEQ (Polling).
GET …/streamServer-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 …/stateGeteilter Zustand (max. 32 KB JSON). POST mit rev prüft die Version → 409 bei Konflikt; optional "broadcast":false.
GET …/snapshotAlles auf einmal: Spieler, Zustand, letztere Event-Sequenz.

Ranglisten (nur Key – Scores sollen fälschungssicher sein)

Methode & PfadZweck
POST · GET /mm/boardsRangliste 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=50Top-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();
Der Raum ist kein Schiedsrichter. Events werden verteilt, aber nicht inhaltlich geprüft. Für fälschungssichere Punkte gilt: dein Backend (mit dem Key) wertet aus und schreibt die Scores in die Rangliste – Spieler-Tokens können dort nichts ändern. Halte Spiellogik also serverseitig oder vereinbare sie im geteilten Zustand.

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

WasGrenze
Speicher pro Entwickler512 MB (alle Dateien zusammen)
Einzelne Datei128 MB
Direkter Upload (PUT ohne Chunks)16 MB
API-Keys pro Entwickler5
Anfragen300 pro Minute (danach 429); Multimode separat: 120 pro Minute
Ordner-Ebenen pro Pfad16
Multimode50 Räume · 32 Spieler/Raum · 10 Tokens/Raum · 20 Ranglisten · 500 Events/Raum
Log-Aufbewahrung30 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

StatusBedeutung & Lösung
401Kein oder falscher Authorization-Header. Schlüssel prüfen, nicht widerrufen? Sonst neu erstellen.
403Konto nicht freigegeben. Bewerbung einreichen und Genehmigung abwarten.
404Datei existiert nicht (Groß-/Kleinschreibung egal, Tippfehler nicht).
409Chunk-Offset passt nicht, Raum voll, Name schon vergeben oder State-Revision veraltet. Mit dem gemeldeten Stand erneut versuchen.
413Quota voll oder Datei > 128 MB. Ältere Dateien löschen bzw. kleiner machen.
429Zu viele Anfragen. Drosseln und mit Verzögerung erneut versuchen.
503Cloud-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.