API

Die sechs vier API liefert die Daten hinter dem Radio: was gerade läuft, was als Nächstes kommt und welche Songs zuletzt gespielt wurden. Sie ist offen, liefert JSON und kann nur lesen.

Überblick

Basis-URLhttps://api.sechs-vier.de
FormatJSON, UTF-8
Zugriffnur lesend (GET), ohne Anmeldung
Aufruf von /Im Browser siehst du eine Übersichtsseite mit Live-Status. Mit dem Header Accept: application/json bekommst du Name, API-Version und Links als JSON.

Zum Befüllen der Daten gibt es außerdem einen Endpunkt, der intern und nicht öffentlich ist. Er steht hier nicht zur Verfügung.

Antwort von GET / mit Accept: application/json
{
  "name": "sechs vier API",
  "description": "Die Daten hinter dem Radio.",
  "version": "1",
  "links": {
    "docs": "https://sechs-vier.de/api/",
    "website": "https://sechs-vier.de/",
    "now": "/now",
    "history": "/history"
  }
}

Jetzt läuft

Zweck: Was läuft gerade, und was kommt als Nächstes? Das ist der Endpunkt für ein „Jetzt läuft“-Widget.

GET https://api.sechs-vier.de/now

Beispiel-Anfrage mit curl
curl -s https://api.sechs-vier.de/now
Beispiel-Anfrage mit fetch
const res = await fetch("https://api.sechs-vier.de/now", { cache: "no-store" });
const now = await res.json();
console.log(now.title, "von", now.artist);
Beispiel-Antwort: ein Song läuft
{
  "id": "34412b69871547e58d1e4695eba9e064",
  "artist": "Muster & Co.",
  "title": "Dritter Beispielsong",
  "cover_url": "https://is1-ssl.mzstatic.com/image/thumb/Music/beispiel3/600x600bb.jpg",
  "artist_img_url": "https://cdn-images.dzcdn.net/images/artist/beispiel/1000x1000-000000-80-0-0.jpg",
  "video_url": "https://video-ssl.itunes.apple.com/itunes-assets/Video/beispiel.m4v",
  "started_at": "2026-11-06T14:15:58Z",
  "kind": "song",
  "duration_sec": 215,
  "next": {
    "artist": "Vierte Band",
    "title": "Vierter Beispielsong",
    "cover_url": "https://is1-ssl.mzstatic.com/image/thumb/Music/beispiel4/600x600bb.jpg"
  },
  "server_time": 1793974653.4
}

Läuft gerade kein Song (Jingle, Spot, Nachrichten, Moderation), ist kind gleich "other", und Artist, Titel und Bilder sind leer:

Beispiel-Antwort: kein Song
{
  "id": "a7c86877c2654c4db3d08107fbcf349e",
  "artist": "",
  "title": "",
  "cover_url": null,
  "artist_img_url": null,
  "video_url": null,
  "started_at": "2026-11-06T14:19:33Z",
  "kind": "other",
  "duration_sec": null,
  "next": null,
  "server_time": 1793974785.8
}

Solange noch nie etwas gelaufen ist, lautet die Antwort null.

FeldTypBedeutung
idTextKennung dieses Eintrags. Ändert sich bei jedem neuen Song.
artistTextInterpret. Bei kind: "other" leer.
titleTextTitel. Bei kind: "other" leer.
cover_urlText oder nullAdresse des Covers (https).
artist_img_urlText oder nullAdresse eines Interpretenbilds (https).
video_urlText oder nullAdresse einer Video-Vorschau (https).
started_atTextStartzeit als ISO 8601 in UTC, zum Beispiel 2026-11-06T14:15:58Z. Sie bezieht sich auf den gehörten Stream (siehe Stream-Delay).
kindText"song" oder "other" (alles, was kein Song ist).
duration_secZahl oder nullLänge in ganzen Sekunden, wenn bekannt.
nextObjekt oder nullDer nächste Song mit artist, title und cover_url. Nur bei laufendem Song gesetzt.
server_timeZahlServerzeit in Sekunden seit 1970 (Unix-Zeit). Damit kannst du den Fortschritt berechnen, ohne der Uhr des Geräts zu vertrauen: server_time - Date.parse(started_at) / 1000.

Zuletzt gespielt

Zweck: Die letzten Songs, neueste zuerst. Der aktuelle Song und alles, was kein Song ist, fehlen.

GET https://api.sechs-vier.de/history?limit=2

ParameterBedeutung
limitAnzahl der Songs, 1 bis 599. Ohne Angabe 20.
Beispiel-Anfrage mit curl
curl -s "https://api.sechs-vier.de/history?limit=2"
Beispiel-Anfrage mit fetch
const res = await fetch("https://api.sechs-vier.de/history?limit=2", { cache: "no-store" });
const songs = await res.json();
songs.forEach((s) => console.log(s.artist, "-", s.title));
Beispiel-Antwort
[
  {
    "id": "c6e75a3c47534c7fbc29b60d5e853771",
    "artist": "Die Beispiele",
    "title": "Zweiter Beispielsong",
    "cover_url": "https://is1-ssl.mzstatic.com/image/thumb/Music/beispiel2/600x600bb.jpg",
    "artist_img_url": null,
    "video_url": null,
    "started_at": "2026-11-06T14:12:40Z",
    "kind": "song",
    "duration_sec": 187
  },
  {
    "id": "a993c8aac308452e87e8042a0e5ff16e",
    "artist": "Beispielband",
    "title": "Erster Beispielsong",
    "cover_url": "https://is1-ssl.mzstatic.com/image/thumb/Music/beispiel1/600x600bb.jpg",
    "artist_img_url": null,
    "video_url": null,
    "started_at": "2026-11-06T14:09:12Z",
    "kind": "song",
    "duration_sec": 201
  }
]

Die Felder sind dieselben wie bei /now, nur next und server_time gibt es hier nicht. Ist die Liste leer, lautet die Antwort [].

Live-Stream der Änderungen

Zweck: Statt ständig nachzufragen, hältst du eine Verbindung offen und bekommst jede Änderung sofort (Server-Sent Events).

GET https://api.sechs-vier.de/events

Beispiel-Anfrage mit curl
curl -s -N https://api.sechs-vier.de/events
Beispiel-Anfrage mit fetch-Ersatz im Browser (EventSource)
const es = new EventSource("https://api.sechs-vier.de/events");
es.addEventListener("now", (e) => {
  const now = JSON.parse(e.data);
  console.log(now.title);
});
es.addEventListener("ping", () => { /* Verbindung lebt */ });
Beispiel-Antwort (gekürzt)
retry: 5000

event: now
data: {"id": "34412b69871547e58d1e4695eba9e064", "artist": "Muster & Co.", "title": "Dritter Beispielsong", "cover_url": "https://is1-ssl.mzstatic.com/image/thumb/Music/beispiel3/600x600bb.jpg", "artist_img_url": "https://cdn-images.dzcdn.net/images/artist/beispiel/1000x1000-000000-80-0-0.jpg", "video_url": "https://video-ssl.itunes.apple.com/itunes-assets/Video/beispiel.m4v", "started_at": "2026-11-06T14:15:58Z", "kind": "song", "duration_sec": 215, "next": {"artist": "Vierte Band", "title": "Vierter Beispielsong", "cover_url": "https://is1-ssl.mzstatic.com/image/thumb/Music/beispiel4/600x600bb.jpg"}, "server_time": 1793974653.4}

: keepalive

event: ping
data: {}
EreignisBedeutung
nowDasselbe Objekt wie bei /now. Kommt direkt nach dem Verbinden und danach bei jeder Änderung.
pingEtwa alle 15 Sekunden ein Lebenszeichen ohne Inhalt ({}).

Zeilen, die mit : beginnen, sind Kommentare, die Verbindungen offen halten. Du kannst sie ignorieren. Kommt länger als 45 Sekunden gar nichts an, ist die Verbindung vermutlich tot: schließen und neu öffnen. Pro Adresse sind höchstens 20 gleichzeitige Streams erlaubt.

Erreichbarkeit

Zweck: Läuft der Dienst?

GET https://api.sechs-vier.de/health

Beispiel-Anfrage mit curl
curl -s https://api.sechs-vier.de/health
Beispiel-Antwort
{
  "ok": true
}

Fehlercodes

Fehler kommen immer als kleines JSON mit dem Feld error. Mehr Details gibt der Dienst bewusst nicht heraus.

StatusBedeutung
404Diesen Pfad gibt es nicht. {"error": "not found"}
405Falsche Methode. Öffentlich geht nur GET.
422Ungültiger Parameter, zum Beispiel limit=abc. {"error": "invalid"}
429Zu viele Anfragen. Der Header Retry-After nennt die Sekunden bis zum nächsten Versuch.
500, 502, 503Der Dienst hat gerade ein Problem oder wird neu gestartet. Später erneut versuchen.
Beispiel-Antwort bei 429
{
  "error": "too many requests"
}

Hinweise

Abfrage-Intervall

Frage /now höchstens alle 5 bis 10 Sekunden ab, besser nutzt du /events. Pro Adresse sind rund 300 Anfragen pro Minute erlaubt. Danach antwortet die API mit 429. Halte dich an Retry-After und mach dann langsamer weiter, statt es sofort noch einmal zu versuchen.

Caching

/now, /history und /events senden Cache-Control: no-store bzw. no-cache. Die Antworten ändern sich laufend, speichere sie nicht zwischen. Frage selbst im Browser mit cache: "no-store" ab.

CORS

Aus dem Browser dürfen nur Seiten von https://sechs-vier.de lesen. Das steht im Header Access-Control-Allow-Origin. Erlaubt ist nur GET. Von einer anderen Website aus blockiert der Browser die Abfrage. Rufe die API dann auf deinem Server ab und gib die Daten von dort weiter. Wenn du einen anderen Anwendungsfall hast, melde dich über die Kontaktseite.

Stream-Delay

Der Livestream kommt mit einigen Sekunden Verzögerung bei dir an. Die API zeigt einen Song deshalb erst an, wenn er im Stream wirklich zu hören ist. Anzeige und Ton passen so zusammen. Du musst nichts umrechnen: started_at gilt für den gehörten Stream, nicht für das Studio.

Cover und Bilder

Die Adressen für Cover, Interpretenbilder und Videos zeigen auf Server der Rechteinhaber und Musikdienste. Sie können sich ändern oder verschwinden. Baue Bilder so ein, dass die Seite auch ohne sie funktioniert.

Einbinden: „Jetzt läuft“-Widget

Ein kleines Beispiel für eine Seite auf sechs-vier.de. Es fragt alle 10 Sekunden ab, setzt Texte immer mit textContent (nie als HTML) und übernimmt nur Bilder mit https. Schlägt eine Abfrage fehl, versucht es später einfach weiter.

HTML und JavaScript
<div id="np" aria-live="polite">
  <img id="np-cover" alt="" width="80" height="80" hidden>
  <p><strong id="np-title"></strong> <span id="np-artist"></span></p>
</div>
<script>
(function () {
  var BASE = "https://api.sechs-vier.de";
  function update() {
    var ctl = new AbortController();
    var t = setTimeout(function () { ctl.abort(); }, 8000);
    fetch(BASE + "/now", { cache: "no-store", signal: ctl.signal })
      .then(function (r) { return r.ok ? r.json() : null; })
      .then(function (n) {
        var song = n && n.kind === "song";
        document.getElementById("np-title").textContent = song ? n.title : "sechs vier";
        document.getElementById("np-artist").textContent = song ? "von " + n.artist : "";
        var img = document.getElementById("np-cover");
        var ok = song && /^https:\/\//.test(n.cover_url || "");
        if (ok) { img.src = n.cover_url; }
        img.hidden = !ok;
      })
      .catch(function () { /* beim nächsten Mal wieder */ })
      .then(function () { clearTimeout(t); setTimeout(update, 10000); });
  }
  update();
})();
</script>

Nutzungsbedingungen

Mehr dazu im Impressum und in der Datenschutzerklärung.

sechs vier

von hier - am Start für euer Studium