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ßerPOST /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 mitproblem. - Limit: 120 Anfragen pro Minute und Schlüssel.
| Status | Bedeutung |
|---|---|
400 | Ungültiger Parameter, z.B. kaputtes Datum |
401 | Schlüssel fehlt, ist falsch oder gelöscht |
403 | Dem Schlüssel fehlt das nötige Recht, oder das Modul ist im Kanal aus ("code": "module_disabled", siehe unten) |
404 | since=stream, aber es gab noch keinen Stream, oder ein TTS-Audio ist abgelaufen |
422 | TTS: Text gesperrt, leer oder unbekannte Stimme |
429 | Zu 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.
| Parameter | Bedeutung |
|---|---|
since | Ab wann (optional) |
until | Bis wann, exklusiv (optional) |
types | Kommagetrennte Event-Typen, z.B. twitch.sub,twitch.cheer |
limit | 1 bis 200, Standard 50 |
cursor | nextCursor 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.
| Pfad | StreamElements-Endpunkt |
|---|---|
activities | Activity-Historie (Parameter after, before, limit, types usw. wie bei StreamElements) |
sessions | Session-Daten: letzter Tip, Top-Spender, Goals, Zähler |
tips/leaderboard | Spender-Rangliste |
points/top, points/alltime | Loyalty-Punkte-Ranglisten |
store/items | Artikel im Loyalty-Store |
contests | Contests |
songrequest/queue, songrequest/playing | Songrequest-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.*- undseventv.*-Events mitevents:read,tts.ready,tts.skipundtts.clearmittts:read,subs.updatedmitsubs:readundspotify.now_playingmitspotify:read. - Werden die Scopes geändert, endet die Verbindung ohne weitere Nachricht. Einfach neu verbinden, dann gelten die neuen Rechte.
replay: truemarkiert erneut abgespielte Events,idundatgibt es bei Events aus dem Eventlog. Über dieiderkennst du Events, die du schon per/eventsgeladen 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
401und403mit kurzer Wartezeit neu, auch bei502oder503. - Wird der Schlüssel gelöscht, kommt
api_key.revokedund 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/streamTTS
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.
Historie + live
Alle Events seit einem Zeitpunkt und danach live, jedes genau einmal
TTS
Texte vorlesen lassen und im Overlay abspielen
© 2026 pixl