API-Dokumentation
Version 1 • Basis-URL: https://ls-tipps.de/api/v1
Format
Alle Anfragen und Antworten verwenden JSON. Sende immer den Header Accept: application/json.
Authentifizierung
Alle Endpunkte erfordern einen Bearer-Token im Authorization-Header.
Authentifizierung
API-Keys werden im Admin-Bereich generiert. Füge den Token bei jeder Anfrage als Bearer-Token im HTTP-Header ein:
Authorization: Bearer DEIN_API_KEY
Accept: application/json
Fehlerbehandlung
Die API gibt standardisierte HTTP-Statuscodes zurück:
| Status | Bedeutung |
|---|---|
200 OK | Anfrage erfolgreich |
201 Created | Ressource wurde erstellt |
401 Unauthorized | Kein oder ungültiger API-Key |
422 Unprocessable | Validierungsfehler – prüfe den errors-Schlüssel im Body |
500 Server Error | Interner Fehler auf dem Server |
Beispiel einer Fehlerantwort (422):
{
"message": "The title field is required.",
"errors": {
"title": ["The title field is required."],
"category_id": ["The selected category id is invalid."]
}
}
/api/v1/categories
Gibt alle verfügbaren Kategorien zurück. Wird benötigt, um beim Erstellen von Beiträgen die korrekte category_id zu ermitteln.
Anfrage-Header
Authorization: Bearer DEIN_API_KEY
Accept: application/json
Beispielantwort
[
{
"id": 1,
"name": "Farming Basics",
"slug": "farming-basics",
"description": "Grundlagen für Einsteiger",
"created_at": "2026-04-09T10:00:00.000000Z",
"updated_at": "2026-04-09T10:00:00.000000Z"
}
]
Codebeispiele
curl -X GET https://ls-tipps.de/api/v1/categories \
-H "Authorization: Bearer DEIN_API_KEY" \
-H "Accept: application/json"
import requests
headers = {
"Authorization": "Bearer DEIN_API_KEY",
"Accept": "application/json",
}
response = requests.get("https://ls-tipps.de/api/v1/categories", headers=headers)
categories = response.json()
for cat in categories:
print(f"{cat['id']}: {cat['name']}")
<?php
$ch = curl_init("https://ls-tipps.de/api/v1/categories");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer DEIN_API_KEY",
"Accept: application/json",
],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
foreach ($response as $category) {
echo $category["id"] . ": " . $category["name"] . "\n";
}
const response = await fetch("https://ls-tipps.de/api/v1/categories", {
headers: {
"Authorization": "Bearer DEIN_API_KEY",
"Accept": "application/json",
},
});
const categories = await response.json();
console.log(categories);
/api/v1/posts
Gibt alle freigegebenen Beiträge paginiert zurück (20 pro Seite), sortiert nach Veröffentlichungsdatum (neueste zuerst).
Query-Parameter
| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
page | integer | 1 | Seitennummer für die Paginierung |
Beispielantwort
{
"current_page": 1,
"data": [
{
"id": 42,
"title": "Effizientes Pflügen im LS25",
"slug": "effizientes-pfluegen-im-ls25",
"excerpt": "Mit dem richtigen Pflug und der passenden Einstellung...",
"category_id": 1,
"tags": ["pflügen", "boden", "ls25"],
"status": "approved",
"ai_model": "claude-sonnet-4-5",
"published_at": "2026-04-10T08:30:00.000000Z",
"category": {
"id": 1,
"name": "Farming Basics",
"slug": "farming-basics"
}
}
],
"per_page": 20,
"total": 93,
"last_page": 5,
"next_page_url": "https://ls-tipps.de/api/v1/posts?page=2"
}
Codebeispiele
curl -X GET "https://ls-tipps.de/api/v1/posts?page=1" \
-H "Authorization: Bearer DEIN_API_KEY" \
-H "Accept: application/json"
import requests
headers = {
"Authorization": "Bearer DEIN_API_KEY",
"Accept": "application/json",
}
page = 1
while True:
r = requests.get(
"https://ls-tipps.de/api/v1/posts",
headers=headers,
params={"page": page},
)
data = r.json()
for post in data["data"]:
print(post["title"])
if not data["next_page_url"]:
break
page += 1
<?php
$page = 1;
do {
$ch = curl_init("https://ls-tipps.de/api/v1/posts?page={$page}");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer DEIN_API_KEY",
"Accept: application/json",
],
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
foreach ($data["data"] as $post) {
echo $post["title"] . "\n";
}
$page++;
} while ($data["next_page_url"]);
async function getAllPosts() {
let page = 1;
let allPosts = [];
while (true) {
const res = await fetch(`https://ls-tipps.de/api/v1/posts?page=${page}`, {
headers: {
"Authorization": "Bearer DEIN_API_KEY",
"Accept": "application/json",
},
});
const data = await res.json();
allPosts = allPosts.concat(data.data);
if (!data.next_page_url) break;
page++;
}
return allPosts;
}
/api/v1/posts
Erstellt einen neuen Beitrag mit Status pending. Der Beitrag landet im Review-Queue und wird von einem Admin freigegeben. Eine Telegram-Benachrichtigung wird automatisch versendet.
Request-Body (JSON)
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
title | string | Ja | Titel des Beitrags (max. 255 Zeichen) |
excerpt | string | Ja | Kurzzusammenfassung für Vorschaukarten |
body | string | Ja | Vollständiger Inhalt als HTML |
category_id | integer | Ja | ID einer existierenden Kategorie |
tags | array | Nein | Liste von Tags als String-Array |
ai_model | string | Nein | Name des verwendeten KI-Modells (max. 100 Zeichen) |
Beispiel-Request
{
"title": "Effizientes Pflügen im LS25",
"excerpt": "Mit dem richtigen Pflug und der passenden Einstellung sparst du Zeit und Kraftstoff.",
"body": "<h2>Einleitung</h2><p>Der Pflug ist eines der wichtigsten Werkzeuge...</p>",
"category_id": 1,
"tags": ["pflügen", "boden", "ls25", "tipps"],
"ai_model": "claude-sonnet-4-5"
}
Beispielantwort 201 Created
{
"id": 42,
"title": "Effizientes Pflügen im LS25",
"slug": null,
"excerpt": "Mit dem richtigen Pflug...",
"status": "pending",
"source": "api",
"ai_model": "claude-sonnet-4-5",
"approved_by": null,
"approved_at": null,
"published_at": null,
"created_at": "2026-04-12T14:22:00.000000Z"
}
Codebeispiele
curl -X POST https://ls-tipps.de/api/v1/posts \
-H "Authorization: Bearer DEIN_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"title": "Effizientes Pflügen im LS25",
"excerpt": "Mit dem richtigen Pflug sparst du Zeit.",
"body": "<h2>Einleitung</h2><p>...</p>",
"category_id": 1,
"tags": ["pflügen", "boden"],
"ai_model": "claude-sonnet-4-5"
}'
import requests
headers = {
"Authorization": "Bearer DEIN_API_KEY",
"Accept": "application/json",
}
payload = {
"title": "Effizientes Pflügen im LS25",
"excerpt": "Mit dem richtigen Pflug sparst du Zeit und Kraftstoff.",
"body": "<h2>Einleitung</h2><p>Der Pflug ist eines der wichtigsten Werkzeuge...</p>",
"category_id": 1,
"tags": ["pflügen", "boden", "ls25"],
"ai_model": "claude-sonnet-4-5",
}
response = requests.post(
"https://ls-tipps.de/api/v1/posts",
headers=headers,
json=payload,
)
if response.status_code == 201:
post = response.json()
print(f"Erstellt: ID {post['id']} – {post['title']}")
else:
print("Fehler:", response.json())
<?php
$payload = json_encode([
"title" => "Effizientes Pflügen im LS25",
"excerpt" => "Mit dem richtigen Pflug sparst du Zeit und Kraftstoff.",
"body" => "<h2>Einleitung</h2><p>Der Pflug ist eines der wichtigsten Werkzeuge...</p>",
"category_id" => 1,
"tags" => ["pflügen", "boden", "ls25"],
"ai_model" => "claude-sonnet-4-5",
]);
$ch = curl_init("https://ls-tipps.de/api/v1/posts");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer DEIN_API_KEY",
"Accept: application/json",
"Content-Type: application/json",
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status === 201) {
echo "Erstellt: ID " . $response["id"] . " – " . $response["title"] . "\n";
} else {
print_r($response["errors"]);
}
const response = await fetch("https://ls-tipps.de/api/v1/posts", {
method: "POST",
headers: {
"Authorization": "Bearer DEIN_API_KEY",
"Accept": "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "Effizientes Pflügen im LS25",
excerpt: "Mit dem richtigen Pflug sparst du Zeit und Kraftstoff.",
body: "<h2>Einleitung</h2><p>Der Pflug ist eines der wichtigsten Werkzeuge...</p>",
category_id: 1,
tags: ["pflügen", "boden", "ls25"],
ai_model: "claude-sonnet-4-5",
}),
});
if (response.status === 201) {
const post = await response.json();
console.log(`Erstellt: ID ${post.id} – ${post.title}`);
} else {
const error = await response.json();
console.error("Validierungsfehler:", error.errors);
}
/api/v1/posts/html-import
Importiert eine HTML-Datei als neuen Beitrag. Titel wird automatisch aus dem <title>-Tag extrahiert, der Excerpt aus den ersten 300 Zeichen. Der Beitrag landet ebenfalls im Review-Queue.
Request-Parameter (multipart/form-data)
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
file | file | Ja | HTML-Datei (.html oder .htm, max. 10 MB) |
category_id | integer | Ja | ID einer existierenden Kategorie |
ai_model | string | Nein | Name des verwendeten KI-Modells |
Beispielantwort 201 Created
{
"id": 43,
"title": "Mein importierter Beitrag",
"excerpt": "Dies ist der automatisch extrahierte Anfangstext...",
"status": "pending",
"source": "html_import",
"ai_model": "claude-opus-4-6",
"created_at": "2026-04-12T15:00:00.000000Z"
}
Codebeispiele
curl -X POST https://ls-tipps.de/api/v1/posts/html-import \
-H "Authorization: Bearer DEIN_API_KEY" \
-H "Accept: application/json" \
-F "file=@/pfad/zu/beitrag.html" \
-F "category_id=1" \
-F "ai_model=claude-opus-4-6"
import requests
headers = {
"Authorization": "Bearer DEIN_API_KEY",
"Accept": "application/json",
}
with open("/pfad/zu/beitrag.html", "rb") as f:
response = requests.post(
"https://ls-tipps.de/api/v1/posts/html-import",
headers=headers,
data={
"category_id": 1,
"ai_model": "claude-opus-4-6",
},
files={"file": ("beitrag.html", f, "text/html")},
)
if response.status_code == 201:
print("Importiert:", response.json()["title"])
else:
print("Fehler:", response.json())
<?php
$ch = curl_init("https://ls-tipps.de/api/v1/posts/html-import");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => [
"file" => new CURLFile("/pfad/zu/beitrag.html", "text/html", "beitrag.html"),
"category_id" => 1,
"ai_model" => "claude-opus-4-6",
],
CURLOPT_HTTPHEADER => [
"Authorization: Bearer DEIN_API_KEY",
"Accept: application/json",
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status === 201
? "Importiert: " . $response["title"] . "\n"
: "Fehler: " . print_r($response["errors"], true);
// Node.js (mit FormData aus dem "form-data" Paket)
import FormData from "form-data";
import fs from "fs";
import fetch from "node-fetch";
const form = new FormData();
form.append("file", fs.createReadStream("/pfad/zu/beitrag.html"), "beitrag.html");
form.append("category_id", "1");
form.append("ai_model", "claude-opus-4-6");
const response = await fetch("https://ls-tipps.de/api/v1/posts/html-import", {
method: "POST",
headers: {
"Authorization": "Bearer DEIN_API_KEY",
"Accept": "application/json",
...form.getHeaders(),
},
body: form,
});
const result = await response.json();
console.log(response.status === 201 ? "Importiert: " + result.title : result);
/api/v1/images
Lädt ein Bild hoch und speichert es auf dem Hetzner Object Storage (S3-kompatibel). Die zurückgegebene URL kann direkt als featured_image beim Erstellen von Beiträgen verwendet werden.
jpg, jpeg, png, gif, webp. Maximale Dateigröße: 10 MB.
Request-Parameter (multipart/form-data)
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
image |
file | Ja | Bilddatei (jpg, png, gif, webp, max. 10 MB) |
Beispielantwort 201 Created
{
"url": "https://your-bucket.fsn1.your-objectstorage.com/images/2026/04/550e8400-e29b-41d4-a716-446655440000.jpg",
"path": "images/2026/04/550e8400-e29b-41d4-a716-446655440000.jpg",
"size": 204800,
"mime": "image/jpeg"
}
Tipp: Bild direkt als featured_image verwenden
{
"title": "Mein Beitrag",
"featured_image": "https://your-bucket.fsn1.your-objectstorage.com/images/2026/04/550e8400.jpg",
"..." : "..."
}
Codebeispiele
curl -X POST https://ls-tipps.de/api/v1/images \
-H "Authorization: Bearer DEIN_API_KEY" \
-H "Accept: application/json" \
-F "image=@/pfad/zu/bild.jpg"
import requests
headers = {
"Authorization": "Bearer DEIN_API_KEY",
"Accept": "application/json",
}
with open("/pfad/zu/bild.jpg", "rb") as f:
response = requests.post(
"https://ls-tipps.de/api/v1/images",
headers=headers,
files={"image": ("bild.jpg", f, "image/jpeg")},
)
if response.status_code == 201:
data = response.json()
print("URL:", data["url"])
else:
print("Fehler:", response.json())
<?php
$ch = curl_init("https://ls-tipps.de/api/v1/images");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => [
"image" => new CURLFile("/pfad/zu/bild.jpg", "image/jpeg", "bild.jpg"),
],
CURLOPT_HTTPHEADER => [
"Authorization: Bearer DEIN_API_KEY",
"Accept: application/json",
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status === 201) {
echo "Hochgeladen: " . $response["url"] . "\n";
} else {
print_r($response["errors"]);
}
// Browser
const input = document.querySelector('input[type="file"]');
const formData = new FormData();
formData.append("image", input.files[0]);
const response = await fetch("https://ls-tipps.de/api/v1/images", {
method: "POST",
headers: {
"Authorization": "Bearer DEIN_API_KEY",
"Accept": "application/json",
},
body: formData,
});
if (response.status === 201) {
const data = await response.json();
console.log("URL:", data.url);
} else {
const error = await response.json();
console.error("Fehler:", error.errors);
}