pixl wird gerade aktiv entwickelt. Was sich ändert, steht in den Neuigkeiten.
pixl

HTTP-API

REST- und Stream-Endpunkte ohne SDK

Das SDK ist nur eine dünne Schicht über diese Endpunkte. Wenn du kein JavaScript im Browser nutzt (z.B. ein Bot oder ein Script auf deinem Rechner), sprichst du sie direkt an.

Grundlagen

  • Basis-URL: https://pixl.lennox.zip/api/v1
  • Authentifizierung: Header Authorization: Bearer pixl_DEIN_SCHLÜSSEL. Einen Query-Parameter für den Schlüssel gibt es bewusst nicht, URLs landen zu leicht in Logs.
  • Alle Endpunkte sind lesend (GET), außer POST /tts. Alle erlauben Aufrufe von fremden Seiten (CORS *, ohne Cookies).
  • Die API liefert nur Daten, sie rechnet nichts aus. Summen o.ä. bildest du selbst aus den Events.
  • Antworten sind JSON. Fehler haben die Form { "error": "..." }, bei TTS zusätzlich mit problem.
  • Limit: 120 Anfragen pro Minute und Schlüssel.
StatusBedeutung
400Ungültiger Parameter, z.B. kaputtes Datum
401Schlüssel fehlt, ist falsch oder gelöscht
403Dem Schlüssel fehlt das nötige Recht, oder das Modul ist im Kanal aus ("code": "module_disabled", siehe unten)
404since=stream, aber es gab noch keinen Stream, oder ein TTS-Audio ist abgelaufen
422TTS: Text gesperrt, leer oder unbekannte Stimme
429Zu viele Anfragen, bei TTS auch: Credits aufgebraucht

Module: Owner und Admins können ganze Funktionen eines Kanals ausschalten (aktuell TTS). Die Endpunkte des Moduls antworten dann mit 403 und { "error": "...", "code": "module_disabled", "problem": "module_disabled", "module": "tts" }. Nach dem Einschalten geht alles wie vorher, der Schlüssel bleibt gültig.

Zeitangaben (since, until, cursor) gehen als ISO-Datum (2026-10-01T18:00:00Z) oder Unix-Millisekunden. since kennt zusätzlich stream für den Start des letzten Streams.

GET /org

Kanal des Schlüssels und seine Scopes. Braucht kein besonderes Recht.

{ "id": "…", "name": "laGameTV", "logo": "https://…", "twitchChannelLogin": "lagametv", "scopes": ["events:read"] }

GET /events

Eventlog, neueste zuerst. Braucht events:read.

ParameterBedeutung
sinceAb wann (optional)
untilBis wann, exklusiv (optional)
typesKommagetrennte Event-Typen, z.B. twitch.sub,twitch.cheer
limit1 bis 200, Standard 50
cursornextCursor der vorherigen Antwort
{
  "events": [
    { "id": "b24f…", "event": "twitch.cheer", "data": { "username": "Kekskruemel698", "bits": 100 }, "at": "2026-10-08T21:48:56.984Z" }
  ],
  "nextCursor": "2026-10-08T21:48:56.984Z"
}

Die Payloads stehen in der Event-Referenz. Erneut abgespielte Events stehen als eigene Zeile drin, erkennbar an data.replay: true.

GET /subs

Aktuelle Sub-Zahl direkt von Twitch, nicht aus dem Eventlog. Braucht subs:read und einen verbundenen Twitch-Kanal. pixl fragt Twitch höchstens einmal pro Minute, die Zahl ist also bis zu 60 Sekunden alt.

{ "total": 312, "points": 340, "at": "2026-10-20T08:15:00.000Z" }

total zählt wie bei Twitch den Streamer selbst mit. points sind die Sub-Punkte (Stufe 1 = 1, Stufe 2 = 2, Stufe 3 = 6). Ändert sich die Zahl, kommt im Stream subs.updated mit denselben Feldern, meist wenige Sekunden nach dem Sub. Ohne verbundenen Kanal oder mit abgelaufener Twitch-Verbindung antwortet der Endpunkt mit 409.

GET /spotify/now-playing

Was gerade auf der verbundenen Spotify-Wiedergabe des Kanals läuft. Braucht spotify:read und das Modul Musik (sonst 403 mit problem: "module_disabled").

{
  "playing": true,
  "progressMs": 83000,
  "at": "2026-10-20T18:02:11.000Z",
  "track": {
    "uri": "spotify:track:4cOdK2wGLETKBW3PvgPWqT",
    "name": "Never Gonna Give You Up",
    "artists": ["Rick Astley"],
    "album": "Whenever You Need Somebody",
    "image": "https://i.scdn.co/image/…",
    "durationMs": 213573,
    "explicit": false,
    "url": "https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT"
  },
  "addedBy": { "name": "lagametv" }
}

progressMs gilt zum Zeitpunkt at. Läuft der Song (playing), rechnest du selbst weiter, das SDK hat dafür Pixl.progress(). Läuft Spotify auf keinem Gerät, ist track null. addedBy ist gesetzt, wenn jemand den Song über pixl in die Queue gelegt hat. Ändert sich etwas (anderer Song, Play/Pause, Sprung im Song), kommt im Stream spotify.now_playing mit denselben Feldern.

pixl fragt Spotify nur ab, solange ein Widget mit spotify:read am Stream hängt: während des Streams alle 5 Sekunden und direkt zum Songende, offline alle 30 Sekunden. Ohne Spotify-Verbindung oder mit abgelaufener Verbindung antwortet der Endpunkt mit 409, bremst Spotify gerade, mit 429.

GET /emotes

Alle Emotes von 7TV, BTTV und FFZ im Kanal, Kanal- und globale Sets. Braucht events:read und einen verbundenen Twitch-Kanal. Gibt es einen Namen mehrfach, steht nur der Gewinner drin (7TV vor BTTV vor FFZ, Kanal vor global). Twitch-Emotes fehlen, die kommen direkt mit jeder Nachricht.

{ "emotes": [{ "provider": "7tv", "id": "01G3WEGZN0000ET2J0MQP5YJ0G", "name": "GAMBA", "animated": true }] }

GET /7tv/paints

Definitionen von 7TV-Paints (farbige Namen), z.B. ?ids=01JHXJFACX42RV996VE9933TB8. Braucht events:read, höchstens 100 IDs pro Abfrage. Welchen Paint ein Chatter trägt, steht als paint in twitch.chat_message.

{
  "paints": [{
    "id": "01JHXJFACX42RV996VE9933TB8",
    "name": "Emerald Doppler",
    "layers": [{ "type": "image", "url": "https://cdn.7tv.app/paint/…/1x.webp", "animated": true, "opacity": 1 }],
    "shadows": [{ "color": "#39D21EFF", "x": 0, "y": 0, "blur": 0.1 }]
  }]
}

Ebenen gibt es als linear-gradient (angle, repeating, stops), radial-gradient (shape, repeating, stops), color und image. Farben als #RRGGBBAA, stops[].at von 0 bis 1, Schatten in px. Das SDK macht daraus CSS (pixl.chat.paintStyle()).

GET /streamelements/{pfad}

Lesender Zugriff auf den StreamElements-Kanal, der mit deinem Kanal verbunden ist. Braucht streamelements:read und einen in den Einstellungen hinterlegten StreamElements Overlay Token. pixl reicht die Anfrage mit diesem Token an StreamElements weiter, der Token selbst bleibt bei pixl. Query-Parameter gehen unverändert mit, die Antwort ist die von StreamElements.

PfadStreamElements-Endpunkt
activitiesActivity-Historie (Parameter after, before, limit, types usw. wie bei StreamElements)
sessionsSession-Daten: letzter Tip, Top-Spender, Goals, Zähler
tips/leaderboardSpender-Rangliste
points/top, points/alltimeLoyalty-Punkte-Ranglisten
store/itemsArtikel im Loyalty-Store
contestsContests
songrequest/queue, songrequest/playingSongrequest-Warteschlange und aktueller Song

Andere Pfade antworten mit 404. Ist StreamElements nicht verbunden, kommt 409. Zusätzlich zum Limit pro Schlüssel gilt hier eins pro Kanal (60 Anfragen pro Minute), weil sich alle Schlüssel denselben StreamElements-Zugang teilen.

curl -H "Authorization: Bearer pixl_…" "https://pixl.lennox.zip/api/v1/streamelements/tips/leaderboard"

GET /stream

Live-Verbindung als Server-Sent Events. Jede Nachricht ist eine data:-Zeile mit JSON:

data: {"orgId":"…","event":"twitch.cheer","data":{"username":"…","bits":100},"id":"…","at":"2026-10-11T19:00:00.000Z"}
  • Was ankommt, hängt von den Scopes ab: twitch.*-, stream.*-, streamelements.*- und seventv.*-Events mit events:read, tts.ready, tts.skip und tts.clear mit tts:read, subs.updated mit subs:read und spotify.now_playing mit spotify:read.
  • Werden die Scopes geändert, endet die Verbindung ohne weitere Nachricht. Einfach neu verbinden, dann gelten die neuen Rechte.
  • replay: true markiert erneut abgespielte Events, id und at gibt es bei Events aus dem Eventlog. Über die id erkennst du Events, die du schon per /events geladen hast.
  • Alle 15 Sekunden kommt ein Kommentar (: ping), damit die Verbindung offen bleibt. Kommt länger als 45 Sekunden gar nichts, ist die Verbindung tot, auch wenn sie noch offen aussieht. Dann einfach neu verbinden.
  • Bei einem Update von pixl endet die Verbindung, und der Server ist ein paar Sekunden nicht erreichbar. Verbinde bei jeder Antwort außer 401 und 403 mit kurzer Wartezeit neu, auch bei 502 oder 503.
  • Wird der Schlüssel gelöscht, kommt api_key.revoked und die Verbindung endet. Danach nicht neu verbinden.

Weil der Schlüssel als Header mitgeht, funktioniert der Browser-eigene EventSource hier nicht. Nutz das SDK, fetch() mit Streaming oder eine SSE-Bibliothek, die Header unterstützt.

curl -N -H "Authorization: Bearer pixl_DEIN_SCHLÜSSEL" https://pixl.lennox.zip/api/v1/stream

TTS

Wie das Ganze zusammenspielt, steht unter TTS.

POST /tts

Text vorlesen lassen. Braucht tts:write, Body als JSON (Content-Type: application/json):

curl -X POST -H "Authorization: Bearer pixl_…" -H "Content-Type: application/json"   -d '{"text": "Danke fürs Einlösen!", "voice": "polly:hans"}'   "https://pixl.lennox.zip/api/v1/tts"

Optional filters: false filtert weder Links noch Wiederholungen noch gesperrte Wörter, oder einzeln als Objekt, z.B. {"links": false} (Schlüssel links, repeats, blockedWords, fehlend = an). Unsichtbare Zeichen und die Längengrenze gelten immer.

Antwort (201): { "id": "…", "text": "Danke fürs Einlösen!", "voice": "polly:hans" }. text ist der bereinigte Text. Danach geht tts.ready an alle Verbindungen mit tts:read. Fehler kommen mit problem, die Werte stehen unter TTS.

GET /tts/voices

Verfügbare Stimmen und die Standardstimme des Kanals. Braucht tts:read oder tts:write.

{ "voices": [{ "id": "polly:hans", "name": "Hans", "language": "de-DE", "gender": "male", "description": "…" }], "default": "polly:hans" }

GET /tts/{id}/audio

Das Audio zu einem tts.ready als MP3. Braucht tts:read. Nach etwa einem Tag gibt es 404.

GET /tts/{id}/marks

Zeitmarken pro Wort zum Audio, für Untertitel, die mitlaufen. Braucht tts:read. Entstehen beim ersten Abruf und kosten dann beim Anbieter extra, danach kommen sie aus dem Zwischenspeicher. Nach etwa einem Tag gibt es 404.

{ "marks": [{ "word": "Lisa", "start": 6, "end": 286 }, { "word": "hat", "start": 286, "end": 473 }, { "word": "Stream", "start": 2654, "end": null }] }

Zeiten in Millisekunden ab Start des Audios. end ist null, wenn es nicht bekannt ist (beim letzten Wort: Ende des Audios).

Events im Stream

data: {"orgId":"…","event":"tts.ready","data":{"id":"…","voice":"polly:hans","text":"Danke fürs Einlösen!","source":"api"},"at":"…"}

data: {"orgId":"…","event":"tts.skip","data":{"id":"…"}}

data: {"orgId":"…","event":"tts.clear","data":{}}

tts.skip ohne id heißt: überspring, was gerade läuft. tts.clear heißt: brich ab, was läuft, und verwirf alles, was wartet. replay: true steht an erneut gesendeten Einträgen.

Auf dieser Seite