# API-Anleitung - Payload CMS ## Übersicht Das Payload CMS stellt eine REST-API und eine GraphQL-API bereit. Diese Anleitung beschreibt die Nutzung der REST-API für die Universal Features. **Base URL:** `https://pl.c2sgmbh.de/api` --- ## Authentifizierung ### Login ```bash curl -X POST "https://pl.c2sgmbh.de/api/users/login" \ -H "Content-Type: application/json" \ -d '{ "email": "admin@example.com", "password": "your-password" }' ``` **Response:** ```json { "message": "Auth Passed", "user": { ... }, "token": "eyJhbGciOiJIUzI1NiIs..." } ``` ### Token verwenden ```bash curl "https://pl.c2sgmbh.de/api/posts" \ -H "Authorization: JWT eyJhbGciOiJIUzI1NiIs..." ``` --- ## Posts API ### Alle Posts abrufen ```bash # Alle Posts curl "https://pl.c2sgmbh.de/api/posts" # Nur Blog-Artikel curl "https://pl.c2sgmbh.de/api/posts?where[type][equals]=blog" # Nur News curl "https://pl.c2sgmbh.de/api/posts?where[type][equals]=news" # Nur veröffentlichte Posts curl "https://pl.c2sgmbh.de/api/posts?where[status][equals]=published" # Nur hervorgehobene Posts curl "https://pl.c2sgmbh.de/api/posts?where[isFeatured][equals]=true" # Mit Sortierung (neueste zuerst) curl "https://pl.c2sgmbh.de/api/posts?sort=-publishedAt" # Limitiert auf 10 Einträge curl "https://pl.c2sgmbh.de/api/posts?limit=10" # Pagination (Seite 2) curl "https://pl.c2sgmbh.de/api/posts?limit=10&page=2" ``` ### Einzelnen Post abrufen ```bash # Nach ID curl "https://pl.c2sgmbh.de/api/posts/1" # Nach Slug (über Query) curl "https://pl.c2sgmbh.de/api/posts?where[slug][equals]=mein-erster-artikel" ``` ### Post erstellen (Auth erforderlich) ```bash curl -X POST "https://pl.c2sgmbh.de/api/posts" \ -H "Authorization: JWT your-token" \ -H "Content-Type: application/json" \ -d '{ "tenant": 1, "title": "Mein neuer Artikel", "slug": "mein-neuer-artikel", "type": "blog", "isFeatured": false, "excerpt": "Eine kurze Zusammenfassung des Artikels...", "content": { "root": { "type": "root", "children": [ { "type": "paragraph", "children": [{ "text": "Der Artikelinhalt..." }] } ] } }, "status": "draft" }' ``` ### Post aktualisieren (Auth erforderlich) ```bash curl -X PATCH "https://pl.c2sgmbh.de/api/posts/1" \ -H "Authorization: JWT your-token" \ -H "Content-Type: application/json" \ -d '{ "status": "published", "publishedAt": "2025-11-30T12:00:00.000Z" }' ``` ### Post löschen (Auth erforderlich) ```bash curl -X DELETE "https://pl.c2sgmbh.de/api/posts/1" \ -H "Authorization: JWT your-token" ``` --- ## Testimonials API ### Alle Testimonials abrufen ```bash # Alle Testimonials curl "https://pl.c2sgmbh.de/api/testimonials" # Nur aktive Testimonials curl "https://pl.c2sgmbh.de/api/testimonials?where[isActive][equals]=true" # Sortiert nach Bewertung (beste zuerst) curl "https://pl.c2sgmbh.de/api/testimonials?sort=-rating" # Sortiert nach eigener Reihenfolge curl "https://pl.c2sgmbh.de/api/testimonials?sort=order" ``` ### Testimonial erstellen (Auth erforderlich) ```bash curl -X POST "https://pl.c2sgmbh.de/api/testimonials" \ -H "Authorization: JWT your-token" \ -H "Content-Type: application/json" \ -d '{ "tenant": 1, "quote": "Hervorragender Service! Ich bin sehr zufrieden.", "author": "Max Mustermann", "role": "Geschäftsführer", "company": "Musterfirma GmbH", "rating": 5, "source": "Google Reviews", "isActive": true, "order": 1 }' ``` --- ## Newsletter Subscribers API ### Newsletter-Anmeldung (Öffentlich) ```bash # Einfache Anmeldung curl -X POST "https://pl.c2sgmbh.de/api/newsletter-subscribers" \ -H "Content-Type: application/json" \ -d '{ "tenant": 1, "email": "kunde@example.com", "source": "website-footer" }' # Mit Namen und Interessen curl -X POST "https://pl.c2sgmbh.de/api/newsletter-subscribers" \ -H "Content-Type: application/json" \ -d '{ "tenant": 1, "email": "kunde@example.com", "firstName": "Max", "lastName": "Mustermann", "interests": ["blog", "products"], "source": "blog-sidebar" }' ``` **Response (Erfolg):** ```json { "doc": { "id": 1, "tenant": 1, "email": "kunde@example.com", "status": "pending", "confirmationToken": "uuid-token-here", "subscribedAt": "2025-11-30T14:23:41.012Z" }, "message": "Newsletter Subscriber successfully created." } ``` ### Subscribers abrufen (Auth erforderlich) ```bash # Alle Subscribers curl "https://pl.c2sgmbh.de/api/newsletter-subscribers" \ -H "Authorization: JWT your-token" # Nur bestätigte Subscribers curl "https://pl.c2sgmbh.de/api/newsletter-subscribers?where[status][equals]=confirmed" \ -H "Authorization: JWT your-token" # Nach E-Mail suchen curl "https://pl.c2sgmbh.de/api/newsletter-subscribers?where[email][equals]=kunde@example.com" \ -H "Authorization: JWT your-token" ``` ### Subscriber bestätigen (Double Opt-In) ```bash # Über Token bestätigen curl -X PATCH "https://pl.c2sgmbh.de/api/newsletter-subscribers/1" \ -H "Authorization: JWT your-token" \ -H "Content-Type: application/json" \ -d '{ "status": "confirmed" }' ``` ### Subscriber abmelden ```bash curl -X PATCH "https://pl.c2sgmbh.de/api/newsletter-subscribers/1" \ -H "Authorization: JWT your-token" \ -H "Content-Type: application/json" \ -d '{ "status": "unsubscribed" }' ``` --- ## Pages API ### Seiten abrufen ```bash # Alle Seiten curl "https://pl.c2sgmbh.de/api/pages" # Seite nach Slug curl "https://pl.c2sgmbh.de/api/pages?where[slug][equals]=startseite" # Nur veröffentlichte Seiten curl "https://pl.c2sgmbh.de/api/pages?where[status][equals]=published" ``` ### Seite mit Blocks Die Blocks werden im `layout`-Array zurückgegeben: ```json { "docs": [{ "id": 1, "title": "Startseite", "slug": "startseite", "layout": [ { "blockType": "hero-block", "title": "Willkommen", "subtitle": "..." }, { "blockType": "posts-list-block", "title": "Aktuelle News", "postType": "news", "limit": 3 }, { "blockType": "testimonials-block", "title": "Das sagen unsere Kunden", "layout": "slider" } ] }] } ``` --- ## Query-Parameter ### Filterung (where) ```bash # Equals ?where[field][equals]=value # Not equals ?where[field][not_equals]=value # Greater than ?where[field][greater_than]=10 # Less than ?where[field][less_than]=100 # Contains (Text) ?where[field][contains]=suchtext # In (Array) ?where[field][in]=value1,value2 # AND-Verknüpfung ?where[and][0][field1][equals]=value1&where[and][1][field2][equals]=value2 # OR-Verknüpfung ?where[or][0][field1][equals]=value1&where[or][1][field2][equals]=value2 ``` ### Sortierung (sort) ```bash # Aufsteigend ?sort=fieldName # Absteigend ?sort=-fieldName # Mehrere Felder ?sort=-publishedAt,title ``` ### Pagination ```bash # Limit ?limit=10 # Seite ?page=2 # Beide kombiniert ?limit=10&page=2 ``` ### Depth (Relations laden) ```bash # Keine Relations laden ?depth=0 # Eine Ebene ?depth=1 # Zwei Ebenen ?depth=2 ``` --- ## Fehlerbehandlung ### Häufige Fehlercodes | Code | Bedeutung | |------|-----------| | 200 | Erfolg | | 201 | Erstellt | | 400 | Ungültige Anfrage | | 401 | Nicht authentifiziert | | 403 | Nicht autorisiert | | 404 | Nicht gefunden | | 500 | Server-Fehler | ### Fehler-Response ```json { "errors": [ { "message": "You are not allowed to perform this action." } ] } ``` ### Validierungsfehler ```json { "errors": [ { "message": "The following field is invalid: email", "field": "email" } ] } ``` --- ## Multi-Tenant Hinweise ### Tenant-ID ermitteln 1. **Admin Panel:** Unter "Settings → Tenants" die ID ablesen 2. **API:** ```bash curl "https://pl.c2sgmbh.de/api/tenants" \ -H "Authorization: JWT your-token" ``` ### Domain-basierter Zugriff Wenn ein Frontend über eine Tenant-Domain (z.B. `porwoll.de`) zugreift, wird der Tenant automatisch erkannt und nur dessen Daten zurückgegeben. ### Manueller Tenant-Filter Für direkte API-Zugriffe: ```bash curl "https://pl.c2sgmbh.de/api/posts?where[tenant][equals]=1" ``` --- ## Beispiel: Frontend-Integration ### Next.js Beispiel ```typescript // lib/api.ts const API_BASE = 'https://pl.c2sgmbh.de/api' const TENANT_ID = 1 export async function getPosts(type?: string, limit = 10) { const params = new URLSearchParams({ 'where[tenant][equals]': String(TENANT_ID), 'where[status][equals]': 'published', limit: String(limit), sort: '-publishedAt', depth: '1', }) if (type && type !== 'all') { params.append('where[type][equals]', type) } const res = await fetch(`${API_BASE}/posts?${params}`) return res.json() } export async function getTestimonials(limit = 6) { const params = new URLSearchParams({ 'where[tenant][equals]': String(TENANT_ID), 'where[isActive][equals]': 'true', limit: String(limit), sort: 'order', depth: '1', }) const res = await fetch(`${API_BASE}/testimonials?${params}`) return res.json() } export async function subscribeNewsletter(email: string, source: string) { const res = await fetch(`${API_BASE}/newsletter-subscribers`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tenant: TENANT_ID, email, source, }), }) return res.json() } ``` ### React Component ```tsx // components/NewsletterForm.tsx import { useState } from 'react' import { subscribeNewsletter } from '@/lib/api' export function NewsletterForm() { const [email, setEmail] = useState('') const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle') const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() setStatus('loading') try { const result = await subscribeNewsletter(email, 'website-footer') if (result.doc) { setStatus('success') setEmail('') } else { setStatus('error') } } catch { setStatus('error') } } return (
setEmail(e.target.value)} placeholder="Ihre E-Mail-Adresse" required /> {status === 'success' &&

Vielen Dank! Bitte bestätigen Sie Ihre E-Mail.

} {status === 'error' &&

Es ist ein Fehler aufgetreten.

}
) } ``` --- ## Rate Limiting Aktuell gibt es kein Rate Limiting. Für Production-Umgebungen sollte ein Reverse Proxy (z.B. Caddy, nginx) mit Rate Limiting konfiguriert werden. --- ## Weitere Ressourcen - **Admin Panel:** https://pl.c2sgmbh.de/admin - **Payload CMS Docs:** https://payloadcms.com/docs - **GraphQL Playground:** https://pl.c2sgmbh.de/api/graphql (wenn aktiviert)