# Feldnachweis: live ermittelte Feldnamen Alle Angaben stammen aus echten API-Antworten vom 20.09.2026, nicht aus Dokumentation. Rohbelege liegen als `docs/beleg-*.json` daneben. --- ## 1. NeuronWriter Basis-URL `https://app.neuronwriter.com/neuron-api/0.5/writer`, Header `X-API-KEY`. ### 1.1 POST /list-projects Aufruf mit leerem Body `{}`. ```json [ {"id":"3da4d745e0e223cb","project":"3da4d745e0e223cb","name":"skrift.de","language":"German","engine":"google.de"} ] ``` Verwendet: `project` = `3da4d745e0e223cb`. Anmerkung: `id` und `project` sind wertgleich, die Doku nennt nur `project`. ### 1.2 POST /new-query Request: `{"project":"...","keyword":"...","engine":"google.de","language":"German"}` Antwort (Beleg: `beleg-01-new-query.json`): ```json { "query": "565abcca58f65e52", "query_url": "https://app.neuronwriter.com/analysis/view/565abcca58f65e52", "share_url": "https://app.neuronwriter.com/analysis/share/565abcca58f65e52/d8418...", "readonly_url": "https://app.neuronwriter.com/analysis/content-preview/565abcca58f65e52/060df..." } ``` **Abweichung vom Auftrag:** Das Feld heisst `query`, nicht `query_id`. Es ist gleichzeitig Request-Parameter aller Folgeaufrufe. ### 1.3 POST /get-query Request: `{"query":"565abcca58f65e52"}` Statuswerte real beobachtet: `in progress` -> `ready`. Die Analyse war nach 7 Polls a 20 Sekunden fertig, also nach rund 2 Minuten. Das konfigurierte Limit von 30 Versuchen entspricht 10 Minuten und ist reichlich. Top-Level-Schluessel der fertigen Antwort (42 KB): ``` ideas, competitors, metrics, terms, terms_txt, status, keyword, language, engine, project, query, serp_summary, query_url, share_url, readonly_url ``` #### Mapping auf die im Auftrag geforderten Felder | Auftrag | Tatsaechlicher Pfad | Struktur | |---|---|---| | `query_id` | `query` | String | | `keyword` | `keyword` | String | | `begriffe_pflicht` | `terms.content_basic` | `[{t, usage_pc, sugg_usage:[min,max]}]` | | `begriffe_erweitert` | `terms.content_extended` | `[{t, usage_pc, sugg_usage:[min,max]}]` | | `fragen` | `ideas.topic_matrix` (Objekt!) + `ideas.people_also_ask` + `ideas.content_questions` + `ideas.suggest_questions` | siehe unten | | `wortzahl_ziel` | `metrics.word_count.target` | Integer (hier 1178) | #### Details, die man nicht raten kann `terms` enthaelt genau diese Schluessel: `title`, `desc`, `h1`, `h2`, `content_basic`, `content_extended`, `entities`. Es gibt **kein** `terms.content`. Die Doku suggeriert das. Beispiel-Eintraege: ```json terms.content_basic[0] = {"t":"handschriftlich","usage_pc":70,"sugg_usage":[1,17]} terms.content_extended[0] = {"t":"handgeschriebene briefe","usage_pc":40,"sugg_usage":[1,5]} terms.h2[0] = {"t":"handschriftlich","usage_pc":50} // kein sugg_usage terms.entities[0] = {"t":"Brief","importance":33.89,"relevance":0.53, "confidence":1.70,"links":[["wikipedia","http://de.wikipedia.org/wiki/Brief"]]} ``` `sugg_usage` ist ein Array `[min, max]`, keine Zahl. `usage_pc` ist der Anteil der Wettbewerber, die den Begriff nutzen, keine Empfehlung. `terms_txt` spiegelt dasselbe als Fliesstext. Schluesselnamen sind hier **nicht identisch**: `title`, `desc_title` (nicht `desc`), `h1`, `h2`, `content_basic`, `content_basic_w_ranges`, `content_extended`, `content_extended_w_ranges`, `entities`. Die `_w_ranges`-Varianten enthalten die Nutzungsspanne direkt im Text (`handschriftlich: 1-17x`) und sind als Schreibvorlage am brauchbarsten. `ideas` hat vier Schluessel, die sich strukturell unterscheiden: ```json ideas.suggest_questions = [] // war im Test LEER ideas.people_also_ask = [{"q":"..."}] // 4 Eintraege ideas.content_questions = [{"q":"..."}] // 28 Eintraege ideas.topic_matrix = {"Frage als Schluessel": {"importance": 10}} // OBJEKT, 10 Eintraege ``` `topic_matrix` ist kein Array. Die Frage steht im Schluessel, die Gewichtung im Wert. In der Doku taucht `topic_matrix` gar nicht auf, obwohl es die wertvollste Quelle ist: die Fragen sind bereits nach Wichtigkeit 1 bis 10 gewichtet. Der Workflow sortiert danach und dedupliziert gegen die anderen drei Quellen. `metrics` hat nur `word_count` und `readability`, beide mit `median` und `target`. Im Test waren `median` und `target` identisch (1178 bzw. 29). `competitors` liefert 31 Eintraege mit `rank, url, title, desc, headers, content_score, readability, word_count, content_len`. `headers` ist ein Array von Zweier-Arrays: `["h2","Text der Ueberschrift"]`. Der Workflow uebernimmt die Gliederungen der Top 5 in den Brief. `serp_summary` ist in der Doku nicht erwaehnt und enthaelt `top_intent` (hier `informational`), `intent_stats`, `top_content_type` (hier `video`) und `content_type_stats` in Prozent. ### 1.4 POST /evaluate-content und /import-content Request laut Doku: `query` plus **`html`** (nicht `content_html`), optional `title`, `description`. Antwort: `{"status":"ok","content_score":}`. Wird in Workflow 2 live gegengeprueft. --- ## 2. n8n - Version `1.120.4`, ermittelt ueber `GET /rest/settings` -> `data.versionCli` - Public API unter `/api/v1` mit Header `X-N8N-API-KEY` funktioniert - `/rest/node-types` und `/types/nodes.json` sind nicht ohne Session-Login erreichbar Verwendete Node-Versionen, verifiziert durch einen importierten und erfolgreich ausgefuehrten Testworkflow: | Node | typeVersion | |---|---| | `n8n-nodes-base.manualTrigger` | 1 | | `n8n-nodes-base.scheduleTrigger` | 1.2 | | `n8n-nodes-base.webhook` | 2.1 | | `n8n-nodes-base.set` | 3.4 | | `n8n-nodes-base.code` | 2 | | `n8n-nodes-base.if` | 2.2 | | `n8n-nodes-base.httpRequest` | 4.3 | | `n8n-nodes-base.splitInBatches` | 3 | | `n8n-nodes-base.wait` | 1.1 | | `n8n-nodes-base.noOp` | 1 | | `n8n-nodes-base.emailSend` | 2.1 | Bei `splitInBatches` v3 ist **Ausgang 0 = done** und **Ausgang 1 = loop**. Vertauschen fuehrt zu einem Workflow, der genau einmal laeuft und dann still endet. **Gelernt beim Testlauf:** Ein Webhook mit `responseMode: "lastNode"` haelt die HTTP-Verbindung bis zum Workflow-Ende offen. Bei Poll-Schleifen laeuft der Reverse Proxy (openresty) nach 60 Sekunden in ein 504, obwohl der Workflow weiterlaeuft. Beide Workflows nutzen deshalb `responseMode: "onReceived"`. --- ## 3. WordPress (skrift.de) Benutzer `ai-agent`, Rolle `editor`, Authentifizierung per Application Password. Geprueft ueber `GET /wp-json/wp/v2/users/me?context=edit`. ### 3.1 Registrierte Meta-Felder Ermittelt ueber `OPTIONS /wp-json/wp/v2/posts`, Pfad `endpoints[].args.meta.properties`. 43 Schluessel registriert. **Vorhanden und direkt ueber `meta` beschreibbar:** ``` _seopress_titles_title (string) _seopress_titles_desc (string) _seopress_analysis_target_kw (string) _seopress_robots_index (string) _seopress_social_fb_title (string) ... sowie 38 weitere _seopress_* und _elementor_* Schluessel ``` **Nicht vorhanden:** `kurzantwort`, `faq`, `cta_ziel`, `stand_datum`. ### 3.2 JetEngine ist auf skrift.de nicht installiert `GET /wp-json/` liefert diese Namespaces: ``` oembed/1.0, skrift/v1, elementor-one/v1, maspik/v1, elementor/v1, elementor-pro/v1, seopress/v1, llar/v1, elementor-hello-elementor/v1, jet-form-builder/v1, elementor/v1/documents, elementor-ai/v1, elementor/v1/feedback, wp/v2, wp-site-health/v1, wp-block-editor/v1, wp-abilities/v1 ``` `jet-form-builder/v1` ist JetFormBuilder, ein anderes Plugin. Es gibt keinen JetEngine-Namespace und `GET /wp-json/wp/v2/types` zeigt keine JetEngine-CPTs. Die im Auftrag genannten JetEngine-Felder existieren also nicht. ### 3.3 Cache-Endpunkt Das Skrift-Plugin registriert nur `GET /skrift/v1/preis`, also keinen Cache-Purge. WP Rocket ist nicht als Namespace sichtbar. Nutzbar ist stattdessen ein echter, vorhandener Endpunkt: ``` POST /wp-json/seopress/v1/commands/clear-cache ``` ### 3.4 Ausgangslage Inhalte `GET /wp-json/wp/v2/posts?status=any` liefert 0 Beitraege. `GET /wp-json/wp/v2/categories` liefert nur `uncategorized` (ID 1). Workflow 2 muss Kategorien also anlegen koennen, nicht nur zuordnen. --- ## 4. Gitea Version `1.25.4`, Repo `lucas.orth/Skrift-Auto-Article`, Default-Branch `main`, leer. Der hinterlegte Token hat die Scopes `read:issue, read:repository`. Schreibende Aufrufe scheitern mit: ```json {"message":"token does not have at least one of required scope(s), required=[write:repository], token scope=read:issue,read:repository"} ``` Benoetigt wird `write:repository`.