API

Integriere QueryWin in deine eigene Pipeline

QueryWin findet die Suchanfragen, für die deine Website bereits Impressionen erhält, aber noch keine passende Seite hat, erstellt einen Entwurf für den fehlenden Artikel und bereitet dein Produkt für die Einreichung in Verzeichnissen, auf Launch-Plattformen, in Communities und auf Websites vor, die KI-Antworten bereits als Quellenangabe verwenden. Diese API übergibt beide Pipelines an deine Skripte und KI-Assistenten. Veröffentlichen und Einreichen erfolgen weiterhin mit deinen eigenen Zugangsdaten und Konten – QueryWin verbindet sich nie mit deinem CMS und reicht selbst nirgendwo etwas ein.

Schnellstart

Drei Schritte. Alles unten ist ein einfacher REST-Aufruf mit einem Header.

1

Schlüssel erstellen

Im QueryWin-Dashboard unter API. Der Schlüssel im Klartext wird beim Erstellen nur einmal angezeigt. Vergib nur die benötigten Scopes — ein Schlüssel ohne gesetzte Kontrollkästchen ist schreibgeschützt.

2

Als Bearer-Token senden

Authorization: Bearer qw_live_… bei jeder Anfrage. X-API-Key funktioniert ebenfalls, wenn dein Tool nur das Setzen eines Headers erlaubt.

3

Lesen, worüber du schreiben solltest, dann den Entwurf abrufen

Die Themenliste ist kostenlos und verbraucht keine Credits. Das Erstellen einer Gliederung oder eines Entwurfs zieht Credits ab und erfordert den Spend-Scope.

bash
# 1. Auf welche Websites dieser Schlüssel zugreifen darf
curl "https://www.querywin.com/api/v1/sites" \
  -H "Authorization: Bearer $QUERYWIN_API_KEY"

# 2. Worüber du diese Woche schreiben solltest (kostenlos, keine Credits)
curl "https://www.querywin.com/api/v1/topics?siteId=YOUR_SITE_ID" \
  -H "Authorization: Bearer $QUERYWIN_API_KEY"
bash
# 3. Den Entwurf abrufen (Markdown + JSON-LD mit ausgefüllten Daten)
curl "https://www.querywin.com/api/v1/topics/article?siteId=YOUR_SITE_ID&key=standard%20wardrobe%20depth" \
  -H "Authorization: Bearer $QUERYWIN_API_KEY"

# 4. Dein Skript veröffentlicht ihn in deinem eigenen Blog und meldet anschließend die URL zurück
curl -X POST https://www.querywin.com/api/v1/topics/published \
  -H "Authorization: Bearer $QUERYWIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "siteId": "YOUR_SITE_ID",
    "key": "standard wardrobe depth",
    "url": "https://example.com/blog/standard-wardrobe-depth"
  }'

Jede Antwort ist verpackt: {"success": true, "data": …}. Fehler sind maschinenlesbare Codes, niemals Fließtext — QueryWin ist zweisprachig, und ein fest codierter englischer Satz würde auf einer chinesischen Seite ausgegeben.

Die Content-Pipeline

Fünf Schritte, und nur zwei davon kosten etwas. Schritt 4 liegt bei dir: QueryWin übergibt dir Markdown und strukturierte Daten, du veröffentlichst sie.

SchrittEndpunktKosten
Finde Suchanfragen mit Impressionen, aber ohne eigene SeiteGET /v1/topicsKostenlos
Eine quellenbasierte Gliederung erstellenPOST /v1/topics/outlineCredits
Daraus einen veröffentlichungsfertigen Entwurf erstellenPOST /v1/topics/articleCredits
In deinem eigenen Blog veröffentlichendein eigenes CMS—
Die URL zurückmeldenPOST /v1/topics/publishedKostenlos

QueryWin verbindet sich nie mit deinem CMS, speichert niemals deine Zugangsdaten und veröffentlicht nie für dich. Diese API übergibt dir die Inhalte; geschrieben wird auf deinem Rechner mit deinen eigenen Zugangsdaten. Das ist die Grenze — keine Lücke darin.

Die Verbreitungs-Pipeline

Sieben Schritte, und nur einer davon kostet etwas. Schritt 6 liegt bei dir: QueryWin übergibt dir das Einreichungsmaterial für jeden Kanal, und du — oder dein Agent mit deinen eigenen Konten — reichst es ein. QueryWin prüft anschließend jeden veröffentlichten Eintrag selbst erneut.

SchrittEndpunktKosten
Deine Produkte und den Vollständigkeitsgrad jedes Profils auflistenGET /v1/productsKostenlos
Einreichungsorte nach Passung auflisten — einschließlich Websites, die in KI-Antworten als Quellenangaben erscheinenGET /v1/channels?productId=Kostenlos
Aus den gewählten Kanälen eine Kampagne erstellenPOST /v1/campaignsKostenlos
Das vorbereitete Material für eine Aufgabe abrufenGET /v1/tasks/{id}Kostenlos
Für diesen Kanal umschreibenPOST /v1/tasks/{id}/materialsCredits
Einreichendeine eigenen Konten—
Einreichung melden, anschließend Veröffentlichung mit der URL des Eintrags meldenPOST /v1/tasks/{id}/statusKostenlos

published ist das, was du gemeldet hast; verified ist das, was QueryWin bei der erneuten Prüfung des Eintrags etwa 72 Stunden später gesehen hat — ein Link zu deinem Produkt in Verzeichnissen und Listen von KI-Tools, andernorts eine Erwähnung. Das sind getrennte Felder. Eine Website, die in KI-Antworten als Quelle erscheint (citedByAi), ist eine Website, bei der sich eine Anfrage lohnt; das ist keine Zusage, dass sie dich aufnimmt.

Scopes

Jeder Schlüssel enthält die bei seiner Erstellung vergebenen Berechtigungen. GET /v1/usage meldet sie, damit du sie nicht erst durch einen 403-Fehler herausfinden musst.

read

Immer aktiv

Jeder GET-Endpunkt: Websites, Content-Lücken, Gliederungen, Entwürfe, Produkte, Kanäle, Kampagnen, Aufgaben und deren Material sowie Nutzung.

publish

Standardmäßig deaktiviert

Produktprofile erstellen und aktualisieren, Bilder importieren und Ergebnisse festhalten: eine veröffentlichte Artikel-URL (auch an Bing, Yandex, Seznam und Naver übermittelt — nicht an Google), eine neue Kampagne oder eine als eingereicht bzw. veröffentlicht markierte Aufgabe. Kostenlos, aber jeder Vorgang ist ein Datensatz mit Folgen: Kampagnen werden auf deinen Tarif angerechnet, und ein veröffentlichter Eintrag wird erneut geprüft.

spend

Standardmäßig deaktiviert

Gliederungen und Entwürfe erstellen und Einreichungsmaterial für einen Kanal umschreiben. Dafür werden Credits abgezogen. Vergib diesen Scope nur, wenn der Aufrufer — ein Skript oder ein KI-Assistent — selbstständig Ausgaben tätigen darf.

Es gibt keine Hierarchie: publish umfasst nicht spend, und spend umfasst nicht publish. Es handelt sich um unterschiedliche Risiken. Ein Aufruf, für den deinem Schlüssel der nötige Scope fehlt, gibt 403 mit missing_scope_<name> und den Scopes zurück, die du besitzt.

Credits ausgeben

Zwei Endpunkte ziehen Credits ab: POST /v1/topics/outline und POST /v1/topics/article. Davor liegen drei Schutzmechanismen.

SchutzmechanismusWas verhindert wird
confirmSpendEin Skript, das nach einer Preiserhöhung weiter abbucht.
TageslimitEine außer Kontrolle geratene Schleife, die das Guthaben über Nacht aufbraucht. Gibt 429 mit dem Zeitpunkt der Zurücksetzung zurück.
Eingabe-FingerabdruckDoppelte Abrechnung für dasselbe Thema. Identische Eingaben geben das zwischengespeicherte Ergebnis kostenlos zurück, sodass ein erneuter Versuch nach einer Zeitüberschreitung sicher ist.

confirmSpend ist eine Autorisierungsobergrenze, kein exakter Betrag. Sende einen Wert, der mindestens dem aktuellen Preis entspricht; berechnet wird, was tatsächlich anfällt — bei einem Cache-Treffer oft null. Sollte der Preis jemals über deine Obergrenze steigen, schlägt der Aufruf mit confirm_spend_too_low fehl, statt stillschweigend mehr abzubuchen.

Konventionen

Drei Dinge, die für jeden Endpunkt gelten.

Antwortformat

json
{ "success": true,  "data": { "...": "..." } }
{ "success": false, "error": "missing_scope_spend" }

Fehler sind Codes, niemals Sätze. Lies sie aus, aber zeige sie nicht unverändert an — sie sollen auf deine eigene Formulierung abgebildet werden.

Geschäftliche Ergebnisse sind keine Fehler

Ein Generierungsaufruf, der kein gültiges Ergebnis erzeugen konnte, gibt HTTP 200 mit data.ok = false und einem data.failure-Code zurück. So kannst du ihn von einem Authentifizierungsfehler oder einer abgebrochenen Verbindung unterscheiden. Dafür werden keine Credits berechnet.

json
{
  "success": true,
  "data": { "ok": false, "failure": "no_outline", "creditsSpent": 0 }
}

Ratenlimit

120 Anfragen pro Minute je Schlüssel. Darüber erhältst du 429 mit dem Zeitpunkt der Zurücksetzung. Dieses Limit gilt unabhängig vom oben genannten täglichen Generierungslimit.

MCP für KI-Agenten

Beide Pipelines sind über das Model Context Protocol verfügbar und werden mit demselben Schlüssel und demselben Header authentifiziert. Füge es zu Claude Code, Cursor, n8n oder jedem anderen Tool hinzu, das MCP über HTTP unterstützt.

MCPhttps://www.querywin.com/api/mcp
bash
claude mcp add --transport http querywin https://www.querywin.com/api/mcp \
  --header "Authorization: Bearer $QUERYWIN_API_KEY"

Neunzehn Tools. Produktprofile: create_product, get_product, update_product, import_product_image. Inhalte: list_sites, get_usage, list_content_gaps, get_outline, get_article_draft, generate_outline, generate_article_draft, mark_published. Frag deine Assistenz, was du diese Woche schreiben solltest oder wo du dein Produkt als Nächstes einreichen kannst – sie findet es heraus.

Prompt
Finde mit dem QueryWin-MCP-Server die drei größten Inhaltslücken auf meiner Website,
zeige mir die Suchanfragen dahinter und sag mir, was es kosten würde, die wichtigste davon als Entwurf zu erstellen.

Die Tools werden nach Berechtigungsumfang gefiltert. Mit einem schreibgeschützten Schlüssel erscheinen die Generierungstools überhaupt nicht in der Tool-Liste der Assistenz – ein Agent kann kein Tool aufrufen, das er nicht sehen kann. Gib einem Agenten einen eigenen Schlüssel, damit du ihn widerrufen kannst, ohne deine anderen Integrationen zu beeinflussen.

Die Authentifizierung erfolgt über ein Bearer-Token, was die MCP-Spezifikation zulässt (die Autorisierung ist dort optional). Clients, bei denen du einen Header festlegen kannst – Claude Code, Cursor, n8n –, verbinden sich direkt. Hosts, die einen OAuth-Zustimmungsbildschirm erfordern, können dies möglicherweise nicht.

Account

GET/v1/sites

Websites auflisten, auf die dieser Schlüssel zugreifen darf

Beginne hier. Jeder andere Endpunkt erwartet die von diesem Aufruf zurückgegebene siteId. Wenn du siteId an anderer Stelle weglässt, wird auf die zuerst verbundene Website zurückgegriffen. Das ist bei Konten mit nur einer Website in Ordnung, bei allen anderen aber ein Fehler, der Probleme verursacht.

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataSiteList
└sitesarray<Site>
└siteIdstring
└domainstring
└gscPropertystringDie Search-Console-Property unverändert: sc-domain:example.com oder https://example.com/.
└syncStatusenumWerte: pendingsyncingdonefailed
└syncedThroughNullwert zulässigstringDie Search Console ist 2–3 Tage im Rückstand. Jede Kennzahl auf dieser Website gilt „Stand“ dieses Datums — erwähne das, wenn du die Zahlen irgendwo anzeigst.
Mögliche Fehler
401Schlüssel fehlt, ist fehlerhaft, widerrufen oder abgelaufen

Beispiel

bash
curl "https://www.querywin.com/api/v1/sites" \
  -H "Authorization: Bearer $QUERYWIN_API_KEY"
json – Antwort
{
  "success": true,
  "data": {
    "sites": [
      {
        "siteId": "string",
        "domain": "example.com",
        "gscProperty": "string",
        "syncStatus": "pending",
        "syncedThrough": "2026-09-01T00:00:00.000Z"
      }
    ]
  }
}
GET/v1/usage

Aktuelle Preise, kostenlose Kontingente, Credit-Guthaben und Tageslimits

Lies dies, bevor du etwas generierst. Es ist dieselbe maßgebliche Quelle, die auch die Weboberfläche verwendet, um den Text auf dem Button festzulegen – die Verfügbarkeit wird serverseitig bestimmt und nicht durch einen erfolglosen Versuch.

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataUsage
└scopesarray<enum>Was dieser Schlüssel darf. Lies dies einmal beim Start ein, statt deine Berechtigungen durch einen 403-Fehler zu ermitteln.Werte: readpublishspend
└creditsobject
└balanceinteger
└outlineStepUsage
└availablebooleanFalse, wenn die Generierungs-Engine nicht konfiguriert ist. Rufe den POST-Endpunkt nicht auf.
└pricePerOutlineintegerCredits pro Gliederung (nur bei outline vorhanden).
└pricePerArticleintegerCredits pro Entwurf (nur bei article vorhanden).
└pricePerTaskintegerCredits pro Kanalüberarbeitung (nur bei materials vorhanden).
└freeRemainingintegerVerbleibende kostenlose Generierungen für dieses Konto, gezählt nach eindeutigem Thema (Gliederungen, Entwürfe) oder eindeutiger Aufgabe (Materialien) — nicht nach Klicks auf Schaltflächen. Auch kostenlose Generierungen erfordern confirmSpend.
└dailyDailyLimitEine Absicherung gegen außer Kontrolle geratene Skripte, die in der Datenbank über alle Kanäle hinweg gezählt wird (auch die Weboberfläche zählt dazu). Sie wird um Mitternacht der lokalen Zeit zurückgesetzt, nicht in einem gleitenden Zeitfenster.
└usedinteger
└limitinteger
└remaininginteger
└resetAtstring
└articleStepUsage
└availablebooleanFalse, wenn die Generierungs-Engine nicht konfiguriert ist. Rufe den POST-Endpunkt nicht auf.
└pricePerOutlineintegerCredits pro Gliederung (nur bei outline vorhanden).
└pricePerArticleintegerCredits pro Entwurf (nur bei article vorhanden).
└pricePerTaskintegerCredits pro Kanalüberarbeitung (nur bei materials vorhanden).
└freeRemainingintegerVerbleibende kostenlose Generierungen für dieses Konto, gezählt nach eindeutigem Thema (Gliederungen, Entwürfe) oder eindeutiger Aufgabe (Materialien) — nicht nach Klicks auf Schaltflächen. Auch kostenlose Generierungen erfordern confirmSpend.
└dailyDailyLimitEine Absicherung gegen außer Kontrolle geratene Skripte, die in der Datenbank über alle Kanäle hinweg gezählt wird (auch die Weboberfläche zählt dazu). Sie wird um Mitternacht der lokalen Zeit zurückgesetzt, nicht in einem gleitenden Zeitfenster.
└usedinteger
└limitinteger
└remaininginteger
└resetAtstring
└materialsStepUsage
└availablebooleanFalse, wenn die Generierungs-Engine nicht konfiguriert ist. Rufe den POST-Endpunkt nicht auf.
└pricePerOutlineintegerCredits pro Gliederung (nur bei outline vorhanden).
└pricePerArticleintegerCredits pro Entwurf (nur bei article vorhanden).
└pricePerTaskintegerCredits pro Kanalüberarbeitung (nur bei materials vorhanden).
└freeRemainingintegerVerbleibende kostenlose Generierungen für dieses Konto, gezählt nach eindeutigem Thema (Gliederungen, Entwürfe) oder eindeutiger Aufgabe (Materialien) — nicht nach Klicks auf Schaltflächen. Auch kostenlose Generierungen erfordern confirmSpend.
└dailyDailyLimitEine Absicherung gegen außer Kontrolle geratene Skripte, die in der Datenbank über alle Kanäle hinweg gezählt wird (auch die Weboberfläche zählt dazu). Sie wird um Mitternacht der lokalen Zeit zurückgesetzt, nicht in einem gleitenden Zeitfenster.
└usedinteger
└limitinteger
└remaininginteger
└resetAtstring
└distributionDistributionQuotaDie Vertriebslimits und die aktuelle Nutzung des Tarifs. Ein Null-Limit bedeutet unbegrenzt.
└planstring
└limitsobject
└channelsNullwert zulässigintegerAnzahl unterschiedlicher Kanäle, für die ein Produkt Aufgaben haben darf, gezählt über channelsPeriod.
└channelsPeriodenummonth (kostenpflichtige Tarife): Zählung pro Kalendermonat (UTC), sodass jeden Monat ein neuer Kanalsatz möglich ist. total (Kostenlos-Tarif): Zählung über die gesamte Lebensdauer des Produkts.Werte: monthtotal
└tasksPerMonthNullwert zulässigintegerAufgaben, die pro Kalendermonat (UTC) über alle Produkte hinweg erstellt werden dürfen.
└activeCampaignsNullwert zulässigintegerKampagnen, die gleichzeitig aktiv sein dürfen.
└usageobject
└activeCampaignsinteger
└tasksThisMonthinteger
└channelsNullwert zulässigintegerNur wenn die Anfrage ein Produkt angegeben hat.
Mögliche Fehler
401Authentifizierung fehlgeschlagen

Beispiel

bash
curl "https://www.querywin.com/api/v1/usage" \
  -H "Authorization: Bearer $QUERYWIN_API_KEY"
json – Antwort
{
  "success": true,
  "data": {
    "scopes": [
      "read"
    ],
    "credits": {
      "balance": 0
    },
    "outline": {
      "available": true,
      "pricePerOutline": 0,
      "pricePerArticle": 0,
      "pricePerTask": 0,
      "freeRemaining": 0,
      "daily": {
        "used": 0,
        "limit": 0,
        "remaining": 0,
        "resetAt": "2026-09-01T00:00:00.000Z"
      }
    },
    "article": {
      "available": true,
      "pricePerOutline": 0,
      "pricePerArticle": 0,
      "pricePerTask": 0,
      "freeRemaining": 0,
      "daily": {
        "used": 0,
        "limit": 0,
        "remaining": 0,
        "resetAt": "2026-09-01T00:00:00.000Z"
      }
    },
    "materials": {
      "available": true,
      "pricePerOutline": 0,
      "pricePerArticle": 0,
      "pricePerTask": 0,
      "freeRemaining": 0,
      "daily": {
        "used": 0,
        "limit": 0,
        "remaining": 0,
        "resetAt": "2026-09-01T00:00:00.000Z"
      }
    },
    "distribution": {
      "plan": "string",
      "limits": {
        "channels": 0,
        "channelsPeriod": "month",
        "tasksPerMonth": 0,
        "activeCampaigns": 0
      },
      "usage": {
        "activeCampaigns": 0,
        "tasksThisMonth": 0,
        "channels": 0
      }
    }
  }
}

Topics

GET/v1/topics

Suchanfragen mit Impressionen, für die noch keine Seite geschrieben wurde

Kostenlos, ohne externe Abrechnung (die API selbst erfordert einen kostenpflichtigen Tarif). Wird bei jedem Aufruf neu anhand deiner eigenen Google Search Console-Daten berechnet – es gibt keine externe Keyword-Datenbank. Genau das ist der Punkt: „Du erhältst bereits Impressionen, hast aber noch keine Seite dazu“ kann dir kein Keyword-Tool sagen.

Die Ergebnisse sind nach Chancen geordnet. Themen, die du in der Benutzeroberfläche verworfen hast, werden ausgeschlossen.

Abfrageparameter

FeldTypBeschreibung
siteIdstringAus GET /v1/sites. Standardmäßig wird die zuerst verbundene Website verwendet.

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataTopicList
└siteIdNullwert zulässigstring
└topicsarray<Topic>
└keystringDer Cluster-Schlüssel – übergib ihn als key an jeden anderen Themen-Endpunkt. Er ist der normalisierte Text der repräsentativen Suchanfrage und kann daher Leerzeichen, Schrägstriche und nichtlateinische Zeichen enthalten. Sende ihn immer in der Query-Zeichenfolge oder im Body, niemals in einem URL-Pfad.
└titlestringDie Suchanfrage mit den meisten Impressionen im Cluster, wortgetreu. Dies ist keine generierte Überschrift – diese wird mit der Gliederung geliefert.
└shapeenumcomparison bedeutet, dass dieser Cluster deine Wettbewerberliste getroffen hat. Der Artikel muss einen Vergleich anstellen, nicht den Wettbewerber erklären – sonst schreibst du Inhalte für ihn.Werte: comparisonroundupguide
└intentstring
└membersarray<TopicMember>
└textstringDie Suchanfrage, wie sie eingegeben wurde.
└impressionsinteger
└clicksinteger
└positionNullwert zulässignumber
└landingUrlNullwert zulässigstringDie Seite, die die Google Search Console derzeit für diese Suchanfrage erfasst, sofern vorhanden.
└impressionsintegerGemessen, aus der Google Search Console.
└clicksintegerGemessen, aus der Google Search Console.
└positionNullwert zulässignumberGemessen: nach Impressionen gewichtete durchschnittliche Position über den gesamten Cluster.
└competitorboolean
└scorenumber
└rankinteger
└upsideClicksintegerEine Schätzung, keine Messung: zusätzliche monatliche Klicks, wenn eine eigene Seite Position 3 erreicht. Dieses Feld ist absichtlich von clicks und impressions getrennt und muss überall, wo du es anzeigst, optisch getrennt bleiben. Eine Prognose als Messwert darzustellen, ist der typische Fehler dieser Produktkategorie.
└statusenumWerte: newdismissedplannedpublished
└outlineAtNullwert zulässigstring
└articleAtNullwert zulässigstringLeite dies nicht aus outlineAt ab. Eine Gliederung bedeutet nicht, dass ein Entwurf vorhanden ist – es handelt sich um zwei getrennte kostenpflichtige Schritte.
└totalQueriesintegerWie viele unterschiedliche Suchanfragen diese Themen insgesamt abdecken.
Mögliche Fehler
401Authentifizierung fehlgeschlagen
404site_not_found – die siteId gehört nicht zu diesem Konto

Beispiel

bash
curl "https://www.querywin.com/api/v1/topics" \
  -H "Authorization: Bearer $QUERYWIN_API_KEY"
json – Antwort
{
  "success": true,
  "data": {
    "siteId": "string",
    "topics": [
      {
        "key": "string",
        "title": "string",
        "shape": "comparison",
        "intent": "string",
        "members": [
          {
            "text": null,
            "impressions": null,
            "clicks": null,
            "position": null,
            "landingUrl": null
          }
        ],
        "impressions": 0,
        "clicks": 0,
        "position": 0,
        "competitor": true,
        "score": 0,
        "rank": 0,
        "upsideClicks": 0,
        "status": "new",
        "outlineAt": "2026-09-01T00:00:00.000Z",
        "articleAt": "2026-09-01T00:00:00.000Z"
      }
    ],
    "totalQueries": 0
  }
}
GET/v1/topics/article

Einen bereits erstellten Entwurf abrufen

Löst niemals eine Generierung aus und kostet nichts. article ist null, wenn noch kein Entwurf vorhanden ist.

Abfrageparameter

FeldTypBeschreibung
keyerforderlichstringDer Cluster-Schlüssel aus GET /v1/topics.
siteIdstringAus GET /v1/sites. Standardmäßig wird die zuerst verbundene Website verwendet.

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataArticleResult
└articleNullwert zulässigArticle
└titlestring
└descriptionstringMeta-Beschreibung.
└markdownstringDer zu veröffentlichende Inhalt.
└jsonLdstringStrukturierte Daten für diesen Artikel, bereits ausgefüllt. Gültiges JSON – füge es auf der veröffentlichten Seite in ein Script-Tag vom Typ application/ld+json ein.
└wordCountinteger
└warningsarray<ArticleWarning>Formulierungen, die wie KI-generiert wirken. Der Entwurf bleibt verwendbar – diese Formulierungen werden gemeldet, statt stillschweigend umgeschrieben zu werden. Protokolliere sie. In einer automatisierten Pipeline ist dies der einzige Moment, in dem jemand sie bemerken könnte.
└kindenumWerte: banned_phrasebanned_wordem_dash_overuseno_short_sentence
└hitstringDer beanstandete Text.
└articleAtNullwert zulässigstring
└modelNullwert zulässigstring
Mögliche Fehler
400key_required
401Authentifizierung fehlgeschlagen

Beispiel

bash
curl "https://www.querywin.com/api/v1/topics/article?key=..." \
  -H "Authorization: Bearer $QUERYWIN_API_KEY"
json – Antwort
{
  "success": true,
  "data": {
    "article": {
      "title": "string",
      "description": "string",
      "markdown": "string",
      "jsonLd": "string",
      "wordCount": 0,
      "warnings": [
        {
          "kind": "banned_phrase",
          "hit": "string"
        }
      ]
    },
    "articleAt": "2026-09-01T00:00:00.000Z",
    "model": "string"
  }
}
POST/v1/topics/article

Die Gliederung in einen veröffentlichungsfähigen Entwurf umwandeln (kostet Credits)

Der teuerste Aufruf im Produkt. Synchron; er kann ein bis zwei Minuten dauern.

Zuerst muss eine Gliederung vorhanden sein – ohne sie erhältst du failure: "no_outline". Die Gliederung enthält die Belege: die tatsächlichen Suchanfragen hinter dem Cluster, die Seiten, die KI aktuell als Quellenangaben verwendet, sowie die Duplikatprüfung gegenüber deinen vorhandenen Seiten. Ohne diesen Schritt wäre es nur ein KI-Schreibwerkzeug ohne Grundlage.

article.markdown ist der zu veröffentlichende Text. article.jsonLd enthält bereits mit den Inhalten dieses Artikels ausgefüllte strukturierte Daten. **article.warnings muss protokolliert werden und darf nicht verworfen werden** – jeder Eintrag verweist auf eine bestimmte Formulierung, die wie KI-generiert wirkt. In einer automatisierten Pipeline liest niemand den Entwurf vor der Veröffentlichung noch einmal durch.

Entwürfe, die die strukturelle Validierung nicht bestehen (fehlende Abschnitte, unbeantwortete Pflichtfragen, erfundene Links, fehlerhaftes JSON-LD), werden verworfen und nicht berechnet.

Anfragetext

FeldTypBeschreibung
keyerforderlichstringDer Cluster-Schlüssel aus GET /v1/topics.
siteIdstringStandardmäßig wird die früheste verbundene Website verwendet.
confirmSpenderforderlichintegerEine Autorisierungs-Obergrenze in Credits, kein exakter Betrag. Sende einen Wert >= dem aktuellen Preis aus GET /v1/usage; berechnet wird, was tatsächlich anfällt, bei einem Treffer aus dem Cache oft null. Falls der Preis deine Obergrenze überschreitet, wird der Aufruf abgelehnt, statt stillschweigend mehr zu berechnen. Erforderlich, auch wenn noch kostenloses Guthaben verfügbar ist – das Guthaben kann aufgebraucht werden, und das sollte nicht der Moment sein, in dem dein Skript erstmals erfährt, dass dieser Endpunkt kostenpflichtig ist. (min 0)

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataArticleOutcome
└okboolean
└failureenumNur vorhanden, wenn ok false ist. HTTP ist weiterhin 200.Werte: topic_not_foundno_outlineengine_unavailableengine_failedno_valid_article
└articleNullwert zulässigArticle
└titlestring
└descriptionstringMeta-Beschreibung.
└markdownstringDer zu veröffentlichende Inhalt.
└jsonLdstringStrukturierte Daten für diesen Artikel, bereits ausgefüllt. Gültiges JSON – füge es auf der veröffentlichten Seite in ein Script-Tag vom Typ application/ld+json ein.
└wordCountinteger
└warningsarray<ArticleWarning>Formulierungen, die wie KI-generiert wirken. Der Entwurf bleibt verwendbar – diese Formulierungen werden gemeldet, statt stillschweigend umgeschrieben zu werden. Protokolliere sie. In einer automatisierten Pipeline ist dies der einzige Moment, in dem jemand sie bemerken könnte.
└kindenumWerte: banned_phrasebanned_wordem_dash_overuseno_short_sentence
└hitstringDer beanstandete Text.
└generatedbooleanFalse, wenn ein zwischengespeichertes Ergebnis zurückgegeben wurde – es wurden keine Credits berechnet.
└creditsSpentinteger
└freeUsedboolean
└rejectedarray<string>Strukturelle Fehler, aufgrund derer ein Entwurf verworfen und nicht berechnet wurde: missing_sections, missing_faq, invented_link, invalid_json_ld, comparison_without_contrast, body_too_short.
Mögliche Fehler
400key_required, confirm_spend_required oder confirm_spend_too_low (der Body enthält den aktuellen price)
401Authentifizierung fehlgeschlagen
402insufficient_credits – der Body enthält requiredCredits, currentBalance und shortfall
403missing_scope_spend — diesem Schlüssel wurde der Bereich spend nicht gewährt
429rate_limited oder daily_limit_reached (der Body enthält resetAt)

Beispiel

bash
curl -X POST https://www.querywin.com/api/v1/topics/article \
  -H "Authorization: Bearer $QUERYWIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "siteId": "clx1site000",
    "key": "standard wardrobe depth",
    "confirmSpend": 80
  }'
json – Antwort
{
  "success": true,
  "data": {
    "ok": true,
    "failure": "topic_not_found",
    "article": {
      "title": "string",
      "description": "string",
      "markdown": "string",
      "jsonLd": "string",
      "wordCount": 0,
      "warnings": [
        {
          "kind": "banned_phrase",
          "hit": "string"
        }
      ]
    },
    "generated": true,
    "creditsSpent": 0,
    "freeUsed": true,
    "rejected": [
      "string"
    ]
  }
}
GET/v1/topics/outline

Eine bereits erstellte Gliederung abrufen

Löst niemals eine Generierung aus und kostet nichts. outline ist null, wenn noch keine Gliederung vorhanden ist.

Abfrageparameter

FeldTypBeschreibung
keyerforderlichstringDer Cluster-Schlüssel aus GET /v1/topics.
siteIdstringAus GET /v1/sites. Standardmäßig wird die zuerst verbundene Website verwendet.

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataOutlineResult
└outlineNullwert zulässigOutline
└titlestring
└slugstring
└anglestringDie Aussage, die diese Seite vermitteln soll.
└sectionsarray<object>
└headingstring
└pointsarray<string>
└faqarray<object>Fragen, die die Seite beantworten muss. Diese dienen als Anknüpfungspunkte, aus denen KI-Antworten zitieren.
└questionstring
└answerstring
└schemaTypestringWelcher JSON-LD-Typ zu dieser Seite passt.
└internalLinksarray<string>Seiten auf deiner eigenen Website, auf die sich ein Link lohnt. Aus echten URLs ausgewählt, niemals erfunden.
└outlineAtNullwert zulässigstring
└modelNullwert zulässigstring
Mögliche Fehler
400key_required
401Authentifizierung fehlgeschlagen

Beispiel

bash
curl "https://www.querywin.com/api/v1/topics/outline?key=..." \
  -H "Authorization: Bearer $QUERYWIN_API_KEY"
json – Antwort
{
  "success": true,
  "data": {
    "outline": {
      "title": "string",
      "slug": "string",
      "angle": "string",
      "sections": [
        {
          "heading": "string",
          "points": []
        }
      ],
      "faq": [
        {
          "question": "string",
          "answer": "string"
        }
      ],
      "schemaType": "string",
      "internalLinks": [
        "string"
      ]
    },
    "outlineAt": "2026-09-01T00:00:00.000Z",
    "model": "string"
  }
}
POST/v1/topics/outline

Eine Gliederung generieren (kostet Credits)

Synchron; rechne mit etwa 10–20 Sekunden.

Identische Eingaben liefern die zwischengespeicherte Gliederung ohne erneute Abrechnung – der Fingerabdruck umfasst den Themencluster und seine Wettbewerberklassifizierung. Das erneute Senden nach einer fehlgeschlagenen HTTP-Anfrage ist daher sicher.

Bei geschäftlichen Ergebnissen (Engine nicht verfügbar, Ausgabe nicht validiert) wird HTTP 200 mit ok: false und einem failure-Code zurückgegeben. Unzureichende Credits führen dagegen zu einem echten 402-Fehler.

Anfragetext

FeldTypBeschreibung
keyerforderlichstringDer Cluster-Schlüssel aus GET /v1/topics.
siteIdstringStandardmäßig wird die früheste verbundene Website verwendet.
confirmSpenderforderlichintegerEine Autorisierungs-Obergrenze in Credits, kein exakter Betrag. Sende einen Wert >= dem aktuellen Preis aus GET /v1/usage; berechnet wird, was tatsächlich anfällt, bei einem Treffer aus dem Cache oft null. Falls der Preis deine Obergrenze überschreitet, wird der Aufruf abgelehnt, statt stillschweigend mehr zu berechnen. Erforderlich, auch wenn noch kostenloses Guthaben verfügbar ist – das Guthaben kann aufgebraucht werden, und das sollte nicht der Moment sein, in dem dein Skript erstmals erfährt, dass dieser Endpunkt kostenpflichtig ist. (min 0)

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataOutlineOutcome
└okboolean
└failureenumNur vorhanden, wenn ok false ist. HTTP ist weiterhin 200 – dies ist ein Ergebnis, kein Fehler.Werte: topic_not_foundengine_unavailableengine_failedno_valid_outline
└outlineNullwert zulässigOutline
└titlestring
└slugstring
└anglestringDie Aussage, die diese Seite vermitteln soll.
└sectionsarray<object>
└headingstring
└pointsarray<string>
└faqarray<object>Fragen, die die Seite beantworten muss. Diese dienen als Anknüpfungspunkte, aus denen KI-Antworten zitieren.
└questionstring
└answerstring
└schemaTypestringWelcher JSON-LD-Typ zu dieser Seite passt.
└internalLinksarray<string>Seiten auf deiner eigenen Website, auf die sich ein Link lohnt. Aus echten URLs ausgewählt, niemals erfunden.
└generatedbooleanFalse, wenn ein zwischengespeichertes Ergebnis zurückgegeben wurde – es wurden keine Credits berechnet.
└creditsSpentinteger
└freeUsedboolean
└rejectedarray<string>Validierungsregeln, gegen die die Modellausgabe verstoßen hat. Als Qualitätssignal solltest du dies protokollieren.
Mögliche Fehler
400key_required, confirm_spend_required oder confirm_spend_too_low (der Body enthält den aktuellen price)
401Authentifizierung fehlgeschlagen
402insufficient_credits – der Body enthält requiredCredits, currentBalance und shortfall
403missing_scope_spend – diesem Schlüssel wurde der Berechtigungsbereich spend nicht erteilt
429rate_limited oder daily_limit_reached (der Body enthält resetAt)

Beispiel

bash
curl -X POST https://www.querywin.com/api/v1/topics/outline \
  -H "Authorization: Bearer $QUERYWIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "siteId": "clx1site000",
    "key": "standard wardrobe depth",
    "confirmSpend": 80
  }'
json – Antwort
{
  "success": true,
  "data": {
    "ok": true,
    "failure": "topic_not_found",
    "outline": {
      "title": "string",
      "slug": "string",
      "angle": "string",
      "sections": [
        {
          "heading": "string",
          "points": []
        }
      ],
      "faq": [
        {
          "question": "string",
          "answer": "string"
        }
      ],
      "schemaType": "string",
      "internalLinks": [
        "string"
      ]
    },
    "generated": true,
    "creditsSpent": 0,
    "freeUsed": true,
    "rejected": [
      "string"
    ]
  }
}
POST/v1/topics/published

Melde, wo du den Artikel veröffentlicht hast

Schließt den Vorgang ab. Markiert das Thema als veröffentlicht, speichert die URL und übermittelt sie in deinem Namen an IndexNow.

IndexNow umfasst Bing, Yandex, Seznam und Naver — nicht Google. Google hat keinen entsprechenden Endpunkt für die sofortige Indexierung; Google findet die Seite über deine Sitemap.

Die IndexNow-Übermittlung lässt die Anfrage nie fehlschlagen: Dein Artikel ist bereits veröffentlicht, und genau das wird durch diesen Aufruf festgehalten. Prüfe das Feld indexnow, um zu sehen, was tatsächlich passiert ist. Für die Übermittlung muss die IndexNow-Schlüsseldatei für die Website verifiziert sein (richte das einmalig im Dashboard ein).

Das Speichern der URL ermöglicht QueryWin außerdem, die Suchanfragen dieses Artikels erneut zu messen, sobald er ausreichend Zeit hatte, sichtbar zu werden.

Anfragetext

FeldTypBeschreibung
keyerforderlichstring
siteIdstring
urlerforderlichstringWo du es veröffentlicht hast. Nur http/https. Zu diesem Zeitpunkt wird die URL nicht abgerufen.

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataPublishedResult
└clusterKeystring
└statusenumWerte: published
└publishedUrlstring
└publishedAtstring
└indexnowobjectBing, Yandex, Seznam, Naver. Nicht Google.
└pushedboolean
└outcomestringskipped bedeutet normalerweise, dass die Schlüsseldatei noch nicht verifiziert ist.
└enginesstring
Mögliche Fehler
400key_required, url_required oder invalid_url (nur http/https)
401Authentifizierung fehlgeschlagen
403missing_scope_publish — diesem Schlüssel wurde der Bereich publish nicht gewährt
404site_not_found

Beispiel

bash
curl -X POST https://www.querywin.com/api/v1/topics/published \
  -H "Authorization: Bearer $QUERYWIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "siteId": "clx1site000",
    "key": "standard wardrobe depth",
    "url": "https://example.com/blog/standard-wardrobe-depth"
  }'
json – Antwort
{
  "success": true,
  "data": {
    "clusterKey": "string",
    "status": "published",
    "publishedUrl": "string",
    "publishedAt": "2026-09-01T00:00:00.000Z",
    "indexnow": {
      "pushed": true,
      "outcome": "string",
      "engines": "string"
    }
  }
}

Distribution

GET/v1/campaigns

Kampagnen und dein Verbreitungskontingent

Kampagnen (archivierte ausgenommen, sofern includeArchived=true nicht gesetzt ist) sowie die Verbreitungsgrenzen und die aktuelle Nutzung deines Tarifs. Kostenlos.

Abfrageparameter

FeldTypBeschreibung
productIdstringNur die Kampagnen dieses Produkts.
includeArchivedboolean

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataCampaignList
└campaignsarray<Campaign>
└campaignIdstring
└productIdstring
└namestring
└statusenumcompleted wird berechnet: Jede Aufgabe wurde veröffentlicht, verifiziert, ist fehlgeschlagen oder wurde übersprungen.Werte: activecompletedarchived
└quotaintegerMit wie vielen Kanälen die Kampagne erstellt wurde.
└startsAtstring
└endsAtNullwert zulässigstring
└countsobject
└totalinteger
└submittedintegereingereicht + veröffentlicht + verifiziert.
└liveintegerveröffentlicht + verifiziert.
└blockedinteger
└doneinteger
└byStatusobject
└createdAtstring
└quotaDistributionQuotaDie Vertriebslimits und die aktuelle Nutzung des Tarifs. Ein Null-Limit bedeutet unbegrenzt.
└planstring
└limitsobject
└channelsNullwert zulässigintegerAnzahl unterschiedlicher Kanäle, für die ein Produkt Aufgaben haben darf, gezählt über channelsPeriod.
└channelsPeriodenummonth (kostenpflichtige Tarife): Zählung pro Kalendermonat (UTC), sodass jeden Monat ein neuer Kanalsatz möglich ist. total (Kostenlos-Tarif): Zählung über die gesamte Lebensdauer des Produkts.Werte: monthtotal
└tasksPerMonthNullwert zulässigintegerAufgaben, die pro Kalendermonat (UTC) über alle Produkte hinweg erstellt werden dürfen.
└activeCampaignsNullwert zulässigintegerKampagnen, die gleichzeitig aktiv sein dürfen.
└usageobject
└activeCampaignsinteger
└tasksThisMonthinteger
└channelsNullwert zulässigintegerNur wenn die Anfrage ein Produkt angegeben hat.
Mögliche Fehler
401Authentifizierung fehlgeschlagen

Beispiel

bash
curl "https://www.querywin.com/api/v1/campaigns" \
  -H "Authorization: Bearer $QUERYWIN_API_KEY"
json – Antwort
{
  "success": true,
  "data": {
    "campaigns": [
      {
        "campaignId": "string",
        "productId": "string",
        "name": "string",
        "status": "active",
        "quota": 0,
        "startsAt": "2026-09-01T00:00:00.000Z",
        "endsAt": "2026-09-01T00:00:00.000Z",
        "counts": {
          "total": 0,
          "submitted": 0,
          "live": 0,
          "blocked": 0,
          "done": 0,
          "byStatus": null
        },
        "createdAt": "2026-09-01T00:00:00.000Z"
      }
    ],
    "quota": {
      "plan": "string",
      "limits": {
        "channels": 0,
        "channelsPeriod": "month",
        "tasksPerMonth": 0,
        "activeCampaigns": 0
      },
      "usage": {
        "activeCampaigns": 0,
        "tasksThisMonth": 0,
        "channels": 0
      }
    }
  }
}
POST/v1/campaigns

Eine Kampagne aus einer ausdrücklich angegebenen Kanalliste erstellen

Pro Kanal-ID wird eine Aufgabe erstellt; das Einreichungsmaterial wird dabei sofort und kostenlos aus dem Produktprofil vorbereitet. Übergib nur die tatsächlich ausgewählten Kanäle — eine Kampagne dokumentiert, wo du dich für eine Einreichung entschieden hast, und ist kein Filter, den der Server erweitert.

Kanäle, für die das Produkt bereits eine offene oder eingereichte Aufgabe hat, werden übersprungen und mit einem Grund (already_open, already_submitted, not_found, broken, inactive, other_product, locked) in skipped aufgeführt. Wenn nichts übrig bleibt, gibt der Aufruf HTTP 200 mit ok: false und failure: "no_valid_targets" zurück. Wird das Verbreitungskontingent des Tarifs überschritten, wird die Anfrage abgelehnt: **409 quota_exceeded** mit dimension, limit, used und requested — es wird nichts erstellt, auch nicht der Teil, der noch hineingepasst hätte.

Anfragetext

FeldTypBeschreibung
productIderforderlichstring
nameerforderlichstring
targetIdserforderlicharray<string>Kanal-IDs aus GET /v1/channels. Nur die ausgewählten Kanäle.
endsAtstringOptionaler im Dashboard angezeigter Stichtag. Nichts wird automatisch geschlossen.

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataCreateCampaignOutcome
└okboolean
└failureenumVorhanden, wenn ok false ist.Werte: no_valid_targets
└campaignCampaign
└campaignIdstring
└productIdstring
└namestring
└statusenumcompleted wird berechnet: Jede Aufgabe wurde veröffentlicht, verifiziert, ist fehlgeschlagen oder wurde übersprungen.Werte: activecompletedarchived
└quotaintegerMit wie vielen Kanälen die Kampagne erstellt wurde.
└startsAtstring
└endsAtNullwert zulässigstring
└countsobject
└totalinteger
└submittedintegereingereicht + veröffentlicht + verifiziert.
└liveintegerveröffentlicht + verifiziert.
└blockedinteger
└doneinteger
└byStatusobject
└createdAtstring
└tasksarray<Task>
└taskIdstring
└campaignIdstring
└productIdstring
└statusenumpublished ist das, was du gemeldet hast. verified ist das, was QueryWin auf der Eintragsseite gesehen hat (ein Link bei Verzeichnissen und KI-Tool-Listen, eine Erwähnung an anderer Stelle). Halte beides in deinen Berichten getrennt.Werte: plannedpreparedin_progressblockedsubmittedpublishedverifiedfailedskipped
└blockedReasonNullwert zulässigenumWerte: logincaptchapaymentmissing_materialothernull
└missingarray<string>Erforderliche Inhalte, die im Produktprofil fehlen. Ergänze das Profil im Dashboard; die Aufgabe bereitet sich selbst erneut vor.
└listingUrlNullwert zulässigstring
└markedByenumWer die letzte Statusänderung vorgenommen hat: eine Person (oder diese API), die Browser-Erweiterung oder QueryWin selbst.Werte: userdevicesystem
└hasGeneratedbooleanEine kanalspezifische Überarbeitung ist vorhanden.
└reviewDueAtNullwert zulässigstringZeitpunkt für die nächste Prüfung nach der Einreichung (submittedAt + die Prüftage des Kanals).
└submittedAtNullwert zulässigstring
└publishedAtNullwert zulässigstring
└verifiedAtNullwert zulässigstring
└nextarray<string>Status, die du über POST /v1/tasks/{id}/status aus dem aktuellen Status setzen kannst.
└targetobject
└targetIdstring
└namestring
└urlstring
└submitUrlstring
└kindstring
└sourceenumWerte: seeduserrivals
└languagestring
└requiresBacklinkboolean
└checkNullwert zulässigobjectDie erneute Prüfung, die QueryWin nach der Veröffentlichung auf dem Eintrag durchführt. Bis zur Veröffentlichung der Aufgabe null.
└kindenumWonach gesucht wird: ein Link zum Produkt (Verzeichnisse, KI-Tool-Listen) oder eine Erwähnung der Marke (alles andere).Werte: link_livemention_seen
└stateNullwert zulässigenumconfirmed = gefunden. unconfirmed = in einer Prüfrunde nicht gefunden (Status bleibt unverändert; prüfe die URL). lost = war vorhanden und ist verschwunden (Aufgabe fehlgeschlagen).Werte: confirmedunconfirmedlostnull
└checkedAtNullwert zulässigstring
└dueAtNullwert zulässigstring
└updatedAtstring
└skippedarray<object>
└targetIdstring
└reasonenumother_product = ein von KI zitierter Kandidat gehört zu einem anderen Produkt; inactive = ein deaktivierter oder ignorierter Kanal; locked = außerhalb des Kanalfensters des Kostenlos-Tarifs (die ersten window Kanäle nach Übereinstimmung, wie von GET /v1/channels zurückgegeben; deine eigenen, bevorzugten und von KI zitierten Kanäle sind nicht begrenzt).Werte: not_foundbrokeninactiveother_productalready_openalready_submittedlocked
Mögliche Fehler
400product_id_required, name_required / name_too_long (80), target_ids_required / too_many_targets (100) oder invalid_date
401Authentifizierung fehlgeschlagen
403missing_scope_publish — diesem Schlüssel wurde der publish-Scope nicht gewährt
404product_not_found — die productId gehört nicht zu diesem Konto
409quota_exceeded — der Body enthält dimension (active_campaigns / tasks_per_month / channels), limit, used, requested; bei channels zusätzlich period (month / total, wie bei VerbreitungQuota.limits.channelsPeriod)

Beispiel

bash
curl -X POST https://www.querywin.com/api/v1/campaigns \
  -H "Authorization: Bearer $QUERYWIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "productId": "clx1prod000",
    "name": "Directories, September",
    "targetIds": [
      "clx1tgt001",
      "clx1tgt002"
    ]
  }'
json – Antwort
{
  "success": true,
  "data": {
    "ok": true,
    "failure": "no_valid_targets",
    "campaign": {
      "campaignId": "string",
      "productId": "string",
      "name": "string",
      "status": "active",
      "quota": 0,
      "startsAt": "2026-09-01T00:00:00.000Z",
      "endsAt": "2026-09-01T00:00:00.000Z",
      "counts": {
        "total": 0,
        "submitted": 0,
        "live": 0,
        "blocked": 0,
        "done": 0,
        "byStatus": null
      },
      "createdAt": "2026-09-01T00:00:00.000Z"
    },
    "tasks": [
      {
        "taskId": "string",
        "campaignId": "string",
        "productId": "string",
        "status": "planned",
        "blockedReason": "login",
        "missing": [
          "string"
        ],
        "listingUrl": "string",
        "markedBy": "user",
        "hasGenerated": true,
        "reviewDueAt": "2026-09-01T00:00:00.000Z",
        "submittedAt": "2026-09-01T00:00:00.000Z",
        "publishedAt": "2026-09-01T00:00:00.000Z",
        "verifiedAt": "2026-09-01T00:00:00.000Z",
        "next": [
          "string"
        ],
        "target": {
          "targetId": "string",
          "name": "string",
          "url": "string",
          "submitUrl": "string",
          "kind": "string",
          "source": "seed",
          "language": "string",
          "requiresBacklink": true
        },
        "check": {
          "kind": "link_live",
          "state": "confirmed",
          "checkedAt": "2026-09-01T00:00:00.000Z",
          "dueAt": "2026-09-01T00:00:00.000Z"
        },
        "updatedAt": "2026-09-01T00:00:00.000Z"
      }
    ],
    "skipped": [
      {
        "targetId": "string",
        "reason": "not_found"
      }
    ]
  }
}
GET/v1/campaigns/{id}

Eine Kampagne mit ihren Aufgaben

Die Kampagne und jede darin enthaltene Aufgabe. Kostenlos.

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataCampaignDetail
└campaignCampaign
└campaignIdstring
└productIdstring
└namestring
└statusenumcompleted wird berechnet: Jede Aufgabe wurde veröffentlicht, verifiziert, ist fehlgeschlagen oder wurde übersprungen.Werte: activecompletedarchived
└quotaintegerMit wie vielen Kanälen die Kampagne erstellt wurde.
└startsAtstring
└endsAtNullwert zulässigstring
└countsobject
└totalinteger
└submittedintegereingereicht + veröffentlicht + verifiziert.
└liveintegerveröffentlicht + verifiziert.
└blockedinteger
└doneinteger
└byStatusobject
└createdAtstring
└tasksarray<Task>
└taskIdstring
└campaignIdstring
└productIdstring
└statusenumpublished ist das, was du gemeldet hast. verified ist das, was QueryWin auf der Eintragsseite gesehen hat (ein Link bei Verzeichnissen und KI-Tool-Listen, eine Erwähnung an anderer Stelle). Halte beides in deinen Berichten getrennt.Werte: plannedpreparedin_progressblockedsubmittedpublishedverifiedfailedskipped
└blockedReasonNullwert zulässigenumWerte: logincaptchapaymentmissing_materialothernull
└missingarray<string>Erforderliche Inhalte, die im Produktprofil fehlen. Ergänze das Profil im Dashboard; die Aufgabe bereitet sich selbst erneut vor.
└listingUrlNullwert zulässigstring
└markedByenumWer die letzte Statusänderung vorgenommen hat: eine Person (oder diese API), die Browser-Erweiterung oder QueryWin selbst.Werte: userdevicesystem
└hasGeneratedbooleanEine kanalspezifische Überarbeitung ist vorhanden.
└reviewDueAtNullwert zulässigstringZeitpunkt für die nächste Prüfung nach der Einreichung (submittedAt + die Prüftage des Kanals).
└submittedAtNullwert zulässigstring
└publishedAtNullwert zulässigstring
└verifiedAtNullwert zulässigstring
└nextarray<string>Status, die du über POST /v1/tasks/{id}/status aus dem aktuellen Status setzen kannst.
└targetobject
└targetIdstring
└namestring
└urlstring
└submitUrlstring
└kindstring
└sourceenumWerte: seeduserrivals
└languagestring
└requiresBacklinkboolean
└checkNullwert zulässigobjectDie erneute Prüfung, die QueryWin nach der Veröffentlichung auf dem Eintrag durchführt. Bis zur Veröffentlichung der Aufgabe null.
└kindenumWonach gesucht wird: ein Link zum Produkt (Verzeichnisse, KI-Tool-Listen) oder eine Erwähnung der Marke (alles andere).Werte: link_livemention_seen
└stateNullwert zulässigenumconfirmed = gefunden. unconfirmed = in einer Prüfrunde nicht gefunden (Status bleibt unverändert; prüfe die URL). lost = war vorhanden und ist verschwunden (Aufgabe fehlgeschlagen).Werte: confirmedunconfirmedlostnull
└checkedAtNullwert zulässigstring
└dueAtNullwert zulässigstring
└updatedAtstring
Mögliche Fehler
401Authentifizierung fehlgeschlagen
404campaign_not_found

Beispiel

bash
curl "https://www.querywin.com/api/v1/campaigns/{id}" \
  -H "Authorization: Bearer $QUERYWIN_API_KEY"
json – Antwort
{
  "success": true,
  "data": {
    "campaign": {
      "campaignId": "string",
      "productId": "string",
      "name": "string",
      "status": "active",
      "quota": 0,
      "startsAt": "2026-09-01T00:00:00.000Z",
      "endsAt": "2026-09-01T00:00:00.000Z",
      "counts": {
        "total": 0,
        "submitted": 0,
        "live": 0,
        "blocked": 0,
        "done": 0,
        "byStatus": null
      },
      "createdAt": "2026-09-01T00:00:00.000Z"
    },
    "tasks": [
      {
        "taskId": "string",
        "campaignId": "string",
        "productId": "string",
        "status": "planned",
        "blockedReason": "login",
        "missing": [
          "string"
        ],
        "listingUrl": "string",
        "markedBy": "user",
        "hasGenerated": true,
        "reviewDueAt": "2026-09-01T00:00:00.000Z",
        "submittedAt": "2026-09-01T00:00:00.000Z",
        "publishedAt": "2026-09-01T00:00:00.000Z",
        "verifiedAt": "2026-09-01T00:00:00.000Z",
        "next": [
          "string"
        ],
        "target": {
          "targetId": "string",
          "name": "string",
          "url": "string",
          "submitUrl": "string",
          "kind": "string",
          "source": "seed",
          "language": "string",
          "requiresBacklink": true
        },
        "check": {
          "kind": "link_live",
          "state": "confirmed",
          "checkedAt": "2026-09-01T00:00:00.000Z",
          "dueAt": "2026-09-01T00:00:00.000Z"
        },
        "updatedAt": "2026-09-01T00:00:00.000Z"
      }
    ]
  }
}
GET/v1/channels

Orte, an denen ein Produkt eingereicht werden kann, nach Eignung sortiert

Die Kanalbibliothek (Verzeichnisse, Launch-Plattformen, KI-Tool-Listen, Communities und Veröffentlichungsplattformen), deine eigenen Einträge und — wenn productId angegeben ist — die Websites, die KI-Antworten für die Suchanfragen dieses Produkts bereits als Quellenangabe nennen (source: "rivals"). Mit productId wird die Liste nach Relevanz sortiert, und jeder Kanal enthält taskStatus (nicht null, wenn für das Produkt dort bereits eine Aufgabe besteht). Kostenlos.

**citedByAi bedeutet, dass KI-Antworten diese Website für deine Suchanfragen als Quelle angegeben haben. Es bedeutet nicht, dass die Website dein Produkt aufnehmen wird** — dafür ist die Aufgabe gedacht, in der du Kontakt aufnimmst.

Abfrageparameter

FeldTypBeschreibung
productIdstringNach Eignung für dieses Produkt sortieren, taskStatus hinzufügen und die von KI zitierten Kandidaten einbeziehen.
kindstringKanaltyp.Werte: directorylaunchai_directorycommunitycontentother
sourcestringseed = Bibliothek, user = von dir hinzugefügt, rivals = von KI zitierte Websites für dieses Produkt.Werte: seeduserrivals
pricingstringKosten der Einreichung.Werte: freeconditionalpaidunknown
submitMethodstringArt der Einreichung: Formular ausfüllen, in einer Community posten oder einen Pitch per E-Mail senden.Werte: formpostemail
qstringNach Name, Domain und Themen suchen.
hideSubmittedbooleanKanäle auslassen, für die dieses Produkt bereits eine offene oder eingereichte Aufgabe hat. Erfordert productId.
pageintegerStandardwert: 1.
pageSizeintegerStandardwert: 30.

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataChannelList
└productIdNullwert zulässigstring
└itemsarray<Channel>
└targetIdstringÜbergib diese Werte als targetIds an POST /v1/campaigns.
└namestring
└urlstring
└submitUrlstringDas Einreichungsformular oder die Veröffentlichungsseite; bei von KI zitierten Websites die Seite, aus der KI-Antworten am häufigsten zitieren.
└kindenumWerte: directorylaunchai_directorycommunitycontentother
└submitMethodenumform = das Einreichungsformular ausfüllen, post = selbst in der Community posten, email = die Redaktion per E-Mail ansprechen (die Adresse wird beim Öffnen aus der Seite gelesen und nicht gespeichert).Werte: formpostemail
└sourceenumseed = aus der Bibliothek, user = von dir hinzugefügt, rivals = eine Website, aus der KI-Antworten bei Suchanfragen für dieses Produkt zitieren.Werte: seeduserrivals
└pricingTypeenumWerte: freeconditionalpaidunknown
└priceNoteNullwert zulässigstring
└languagestringen, zh, multi oder ein Sprachcode, der bei von KI zitierten Websites aus den Suchanfragen erkannt wurde.
└topicsarray<string>
└requiresAccountboolean
└requiresBacklinkboolean
└reviewDaysNullwert zulässigintegerÜbliche Prüfungsdauer. Die Aufgabe erinnert dich daran, danach erneut nachzusehen.
└siteRankNullwert zulässigintegerGlobale Position in der öffentlichen Tranco-Liste (niedriger = häufiger besucht). null = außerhalb der ersten Million. Dies ist nicht die Domainbewertung.
└hasFormSpecbooleanDie Formularfelder des Kanals sind registriert, sodass die Inhalte exakt auf ihre Limits zugeschnitten werden.
└relevanceNullwert zulässigintegerPassgenauigkeitswert für das in der Anfrage genannte Produkt. Nur zur Sortierung.
└taskStatusNullwert zulässigstringDie offene oder abgeschlossene Aufgabe des Produkts für diesen Kanal, sofern vorhanden. null = noch keine.
└citedByAiNullwert zulässigobjectNur für source: "rivals". KI-Antworten haben diese Website bei den aufgeführten Suchanfragen zitiert. Dies ist kein Versprechen, dass die Website dein Produkt aufnimmt – genau dafür ist die Aufgabe da.
└queriesintegerFür wie viele unterschiedliche Suchanfragen die Website zitiert wurde.
└samplesintegerWie viele KI-Antwortsbeispiele die Website zitiert haben.
└searchesarray<string>
└pagesarray<string>Die zitierten Seiten, zuerst die am häufigsten zitierten. Bei älteren Beispielen leer, wenn nur die Domain erfasst wurde.
└totalinteger
└pageinteger
└pageSizeinteger
└limitedbooleanKostenlos-Tarif: Nur die ersten window Kanäle in der Standardreihenfolge (beste Übereinstimmung mit productId) werden zurückgegeben; die Parameter für Filter, Suche und Sortierung werden mit 403 library_locked abgelehnt. total enthält weiterhin die Größe der vollständigen Bibliothek.
└windowNullwert zulässigintegerUmfang des kostenlosen Tarifs: 20 Kanäle, plus 20 für jeden über deinen Einladungslink registrierten Freund (und 20, wenn du dich selbst über einen solchen Link registriert hast). null, wenn die Liste nicht begrenzt ist.
Mögliche Fehler
401Authentifizierung fehlgeschlagen

Beispiel

bash
curl "https://www.querywin.com/api/v1/channels" \
  -H "Authorization: Bearer $QUERYWIN_API_KEY"
json – Antwort
{
  "success": true,
  "data": {
    "productId": "string",
    "items": [
      {
        "targetId": "string",
        "name": "string",
        "url": "string",
        "submitUrl": "string",
        "kind": "directory",
        "submitMethod": "form",
        "source": "seed",
        "pricingType": "free",
        "priceNote": "string",
        "language": "string",
        "topics": [
          "string"
        ],
        "requiresAccount": true,
        "requiresBacklink": true,
        "reviewDays": 0,
        "siteRank": 0,
        "hasFormSpec": true,
        "relevance": 0,
        "taskStatus": "string",
        "citedByAi": {
          "queries": 0,
          "samples": 0,
          "searches": [],
          "pages": []
        }
      }
    ],
    "total": 0,
    "page": 0,
    "pageSize": 0,
    "limited": true,
    "window": 0
  }
}
GET/v1/products

Deine Produkte und der Fertigstellungsgrad ihrer Profile

Beginne hier mit der Vertriebspipeline; jeder weitere Vertriebsendpunkt benötigt eine productId. completeness und missing stammen aus dem gespeicherten Produktprofil: Ein leeres Feld dort bleibt in jeder Einreichung leer, und erforderliche Lücken stoppen eine Aufgabe mit blocked / missing_material, bis das Profil vervollständigt ist. Lies es mit GET /v1/products/{id} und ergänze es mit PATCH /v1/products/{id}. Kostenlos.

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataProductList
└productsarray<Product>
└productIdstring
└namestring
└urlstring
└domainstring
└primaryLanguageenumWerte: enzhjakodefresptitrunlpltrarthviid
└topicsarray<string>
└completenessintegerVollständigkeit des Produktprofils, 0–100. Ergänze fehlende Felder im Dashboard oder mit PATCH /v1/products/{id}.
└missingarray<string>Leere Felder des Produktprofils. Jedes davon ist eine Lücke bei jeder Einreichung.
└sitesarray<object>
└siteIdstring
└domainstring
└syncedThroughNullwert zulässigstring
Mögliche Fehler
401Authentifizierung fehlgeschlagen

Beispiel

bash
curl "https://www.querywin.com/api/v1/products" \
  -H "Authorization: Bearer $QUERYWIN_API_KEY"
json – Antwort
{
  "success": true,
  "data": {
    "products": [
      {
        "productId": "string",
        "name": "string",
        "url": "string",
        "domain": "string",
        "primaryLanguage": "en",
        "topics": [
          "string"
        ],
        "completeness": 0,
        "missing": [
          "string"
        ],
        "sites": [
          {
            "siteId": null,
            "domain": null,
            "syncedThrough": null
          }
        ]
      }
    ]
  }
}
POST/v1/products

Produkt erstellen

Erfordert den Bereich publish und einen kostenpflichtigen Tarif. Erstellt aus einer öffentlichen Homepage-URL und optional einem Namen ein Produkt; verwendet dein Produktkontingent und kostet keine Credits. Gibt das vollständig gespeicherte Produktprofil zurück. Ergänze es anschließend mit PATCH /v1/products/{id}. Führt weder Crawling noch KI aus. Eine doppelte Domain gibt 409 product_exists mit der vorhandenen productId zurück; verwende diese nach einer verlorenen Antwort erneut. Produktvoreinstellungen sind bearbeitbare Werte und keine verifizierten Fakten über die Website.

Anfragetext

FeldTypBeschreibung
urlerforderlichstring
namestring

Antwort201

FeldTypBeschreibung
successboolean
dataProductDetail
└namestring
└urlstring
└primaryLanguageenumWerte: enzhjakodefresptitrunlpltrarthviid
└businessTypeenumWerte: saastoolecommercecontentserviceother
└launchStatusenumWerte: livebeta
└pricingModelenumWerte: freefreemiumpaidtrial
└taglineNullwert zulässigobject
└shortDescNullwert zulässigobject
└longDescNullwert zulässigobject
└firstCommentNullwert zulässigobject
└topicsarray<string>
└promoCodeNullwert zulässigstring
└videoUrlNullwert zulässigstring
└demoUrlNullwert zulässigstring
└linksNullwert zulässigobject
└webAppstring
└appStorestring
└playStorestring
└chromeExtensionstring
└macosstring
└windowsstring
└socialsNullwert zulässigobject
└xstring
└linkedinstring
└githubstring
└instagramstring
└youtubestring
└facebookstring
└contactNameNullwert zulässigstring
└contactEmailNullwert zulässigstring
└galleryarray<string>
└productIdstring
└domainstring
└thumbnailUrlNullwert zulässigstring
└completenessinteger (0–100)
└missingarray<string>
└createdAtstring
└updatedAtstring
└sitesarray<object>
└siteIdstring
└domainstring
└syncedThroughNullwert zulässigstring
Mögliche Fehler
400invalid_product_input, invalid_url, url_not_public
401Authentifizierung fehlgeschlagen
403plan_required oder bei Schreibvorgängen missing_scope_publish
409product_exists (enthält die vorhandene productId) oder product_limit_reached
429rate_limited — 120 Anfragen pro Minute und Schlüssel

Beispiel

bash
curl -X POST https://www.querywin.com/api/v1/products \
  -H "Authorization: Bearer $QUERYWIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "name": "Example"
  }'
json – Antwort
{
  "success": true,
  "data": {
    "name": "string",
    "url": "string",
    "primaryLanguage": "en",
    "businessType": "saas",
    "launchStatus": "live",
    "pricingModel": "free",
    "tagline": null,
    "shortDesc": null,
    "longDesc": null,
    "firstComment": null,
    "topics": [
      "string"
    ],
    "promoCode": "string",
    "videoUrl": "string",
    "demoUrl": "string",
    "links": {
      "webApp": "string",
      "appStore": "string",
      "playStore": "string",
      "chromeExtension": "string",
      "macos": "string",
      "windows": "string"
    },
    "socials": {
      "x": "string",
      "linkedin": "string",
      "github": "string",
      "instagram": "string",
      "youtube": "string",
      "facebook": "string"
    },
    "contactName": "string",
    "contactEmail": "string",
    "gallery": [
      "string"
    ],
    "productId": "string",
    "domain": "string",
    "thumbnailUrl": "string",
    "completeness": 0,
    "missing": [
      "string"
    ],
    "createdAt": "2026-09-01T00:00:00.000Z",
    "updatedAt": "2026-09-01T00:00:00.000Z",
    "sites": [
      {
        "siteId": "string",
        "domain": "string",
        "syncedThrough": "string"
      }
    ]
  }
}
PATCH/v1/products/{id}

Produktprofil ergänzen oder aktualisieren

Erfordert den Bereich publish. Speichert nur übergebene Felder sofort; Objekte (einschließlich lokalisierter Texte) und Arrays ersetzen das gesamte Feld. Lies das Profil zuerst aus, damit andere Sprachen erhalten bleiben. Keine Credits und keine KI-Generierung. Ausstehende Einreichungsinhalte werden asynchron aktualisiert. Verwende nur bekannte Fakten und erfinde keine fehlenden Produktdetails.

Anfragetext

FeldTypBeschreibung
namestring
urlstring
primaryLanguageenumWerte: enzhjakodefresptitrunlpltrarthviid
businessTypeenumWerte: saastoolecommercecontentserviceother
launchStatusenumWerte: livebeta
pricingModelenumWerte: freefreemiumpaidtrial
taglineobject
shortDescobject
longDescobject
firstCommentobject
topicsarray<string>
promoCodestring
videoUrlstring
demoUrlstring
linksobject
└webAppstring
└appStorestring
└playStorestring
└chromeExtensionstring
└macosstring
└windowsstring
socialsobject
└xstring
└linkedinstring
└githubstring
└instagramstring
└youtubestring
└facebookstring
contactNamestring
contactEmailstring
galleryarray<string>

Antwort200

FeldTypBeschreibung
successboolean
dataProductDetail
└namestring
└urlstring
└primaryLanguageenumWerte: enzhjakodefresptitrunlpltrarthviid
└businessTypeenumWerte: saastoolecommercecontentserviceother
└launchStatusenumWerte: livebeta
└pricingModelenumWerte: freefreemiumpaidtrial
└taglineNullwert zulässigobject
└shortDescNullwert zulässigobject
└longDescNullwert zulässigobject
└firstCommentNullwert zulässigobject
└topicsarray<string>
└promoCodeNullwert zulässigstring
└videoUrlNullwert zulässigstring
└demoUrlNullwert zulässigstring
└linksNullwert zulässigobject
└webAppstring
└appStorestring
└playStorestring
└chromeExtensionstring
└macosstring
└windowsstring
└socialsNullwert zulässigobject
└xstring
└linkedinstring
└githubstring
└instagramstring
└youtubestring
└facebookstring
└contactNameNullwert zulässigstring
└contactEmailNullwert zulässigstring
└galleryarray<string>
└productIdstring
└domainstring
└thumbnailUrlNullwert zulässigstring
└completenessinteger (0–100)
└missingarray<string>
└createdAtstring
└updatedAtstring
└sitesarray<object>
└siteIdstring
└domainstring
└syncedThroughNullwert zulässigstring
Mögliche Fehler
400invalid_product_input, invalid_url, url_not_public, invalid_email oder invalid_gallery
401Authentifizierung fehlgeschlagen
403plan_required oder bei Schreibvorgängen missing_scope_publish
404product_not_found
409product_exists (enthält die vorhandene productId)
429rate_limited — 120 Anfragen pro Minute und Schlüssel

Beispiel

bash
curl -X PATCH https://www.querywin.com/api/v1/products/{id} \
  -H "Authorization: Bearer $QUERYWIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tagline": {
      "en": "Your product tagline",
      "zh": "你的产品标语"
    },
    "shortDesc": {
      "en": "A factual description of the product."
    },
    "topics": [
      "productivity",
      "developer-tools"
    ],
    "contactEmail": "hello@example.com"
  }'
json – Antwort
{
  "success": true,
  "data": {
    "name": "string",
    "url": "string",
    "primaryLanguage": "en",
    "businessType": "saas",
    "launchStatus": "live",
    "pricingModel": "free",
    "tagline": null,
    "shortDesc": null,
    "longDesc": null,
    "firstComment": null,
    "topics": [
      "string"
    ],
    "promoCode": "string",
    "videoUrl": "string",
    "demoUrl": "string",
    "links": {
      "webApp": "string",
      "appStore": "string",
      "playStore": "string",
      "chromeExtension": "string",
      "macos": "string",
      "windows": "string"
    },
    "socials": {
      "x": "string",
      "linkedin": "string",
      "github": "string",
      "instagram": "string",
      "youtube": "string",
      "facebook": "string"
    },
    "contactName": "string",
    "contactEmail": "string",
    "gallery": [
      "string"
    ],
    "productId": "string",
    "domain": "string",
    "thumbnailUrl": "string",
    "completeness": 0,
    "missing": [
      "string"
    ],
    "createdAt": "2026-09-01T00:00:00.000Z",
    "updatedAt": "2026-09-01T00:00:00.000Z",
    "sites": [
      {
        "siteId": "string",
        "domain": "string",
        "syncedThrough": "string"
      }
    ]
  }
}
GET/v1/products/{id}

Vollständiges Produktprofil abrufen

Gibt lokalisierte Texte, Links, Kontaktdaten, Bilder, Vollständigkeit und fehlende Felder des gespeicherten Profils zurück. Lesebereich; keine Credits. Ein Produkt außerhalb dieses Arbeitsbereichs gibt ebenfalls product_not_found zurück.

Antwort200

FeldTypBeschreibung
successboolean
dataProductDetail
└namestring
└urlstring
└primaryLanguageenumWerte: enzhjakodefresptitrunlpltrarthviid
└businessTypeenumWerte: saastoolecommercecontentserviceother
└launchStatusenumWerte: livebeta
└pricingModelenumWerte: freefreemiumpaidtrial
└taglineNullwert zulässigobject
└shortDescNullwert zulässigobject
└longDescNullwert zulässigobject
└firstCommentNullwert zulässigobject
└topicsarray<string>
└promoCodeNullwert zulässigstring
└videoUrlNullwert zulässigstring
└demoUrlNullwert zulässigstring
└linksNullwert zulässigobject
└webAppstring
└appStorestring
└playStorestring
└chromeExtensionstring
└macosstring
└windowsstring
└socialsNullwert zulässigobject
└xstring
└linkedinstring
└githubstring
└instagramstring
└youtubestring
└facebookstring
└contactNameNullwert zulässigstring
└contactEmailNullwert zulässigstring
└galleryarray<string>
└productIdstring
└domainstring
└thumbnailUrlNullwert zulässigstring
└completenessinteger (0–100)
└missingarray<string>
└createdAtstring
└updatedAtstring
└sitesarray<object>
└siteIdstring
└domainstring
└syncedThroughNullwert zulässigstring
Mögliche Fehler
401Authentifizierung fehlgeschlagen
403plan_required oder bei Schreibvorgängen missing_scope_publish
404product_not_found
429rate_limited — 120 Anfragen pro Minute und Schlüssel

Beispiel

bash
curl "https://www.querywin.com/api/v1/products/{id}" \
  -H "Authorization: Bearer $QUERYWIN_API_KEY"
json – Antwort
{
  "success": true,
  "data": {
    "name": "string",
    "url": "string",
    "primaryLanguage": "en",
    "businessType": "saas",
    "launchStatus": "live",
    "pricingModel": "free",
    "tagline": null,
    "shortDesc": null,
    "longDesc": null,
    "firstComment": null,
    "topics": [
      "string"
    ],
    "promoCode": "string",
    "videoUrl": "string",
    "demoUrl": "string",
    "links": {
      "webApp": "string",
      "appStore": "string",
      "playStore": "string",
      "chromeExtension": "string",
      "macos": "string",
      "windows": "string"
    },
    "socials": {
      "x": "string",
      "linkedin": "string",
      "github": "string",
      "instagram": "string",
      "youtube": "string",
      "facebook": "string"
    },
    "contactName": "string",
    "contactEmail": "string",
    "gallery": [
      "string"
    ],
    "productId": "string",
    "domain": "string",
    "thumbnailUrl": "string",
    "completeness": 0,
    "missing": [
      "string"
    ],
    "createdAt": "2026-09-01T00:00:00.000Z",
    "updatedAt": "2026-09-01T00:00:00.000Z",
    "sites": [
      {
        "siteId": "string",
        "domain": "string",
        "syncedThrough": "string"
      }
    ]
  }
}
POST/v1/products/{id}/images/from-url

Produktbild aus einer URL importieren

Erfordert den Bereich publish. Ruft ein öffentliches HTTP(S)-Bild ab und speichert eine Kopie als Miniaturbild (ersetzt das vorhandene) oder in der Galerie (fügt es hinzu, höchstens sechs Bilder). JPEG, PNG, WebP und SVG, höchstens 4 MB; SVG wird in PNG umgewandelt. Private Netzwerke und unsichere Weiterleitungen blockiert der vorhandene Bildabruf. Keine Credits. Wiederholte Galerieimporte können Duplikate hinzufügen; rufe das Produkt nach einer verlorenen Antwort mit GET ab, bevor du es erneut versuchst.

Anfragetext

FeldTypBeschreibung
urlerforderlichstring
kindenumWerte: thumbnailgalleryStandardwert gallery

Antwort200

FeldTypBeschreibung
successboolean
dataProductDetail
└namestring
└urlstring
└primaryLanguageenumWerte: enzhjakodefresptitrunlpltrarthviid
└businessTypeenumWerte: saastoolecommercecontentserviceother
└launchStatusenumWerte: livebeta
└pricingModelenumWerte: freefreemiumpaidtrial
└taglineNullwert zulässigobject
└shortDescNullwert zulässigobject
└longDescNullwert zulässigobject
└firstCommentNullwert zulässigobject
└topicsarray<string>
└promoCodeNullwert zulässigstring
└videoUrlNullwert zulässigstring
└demoUrlNullwert zulässigstring
└linksNullwert zulässigobject
└webAppstring
└appStorestring
└playStorestring
└chromeExtensionstring
└macosstring
└windowsstring
└socialsNullwert zulässigobject
└xstring
└linkedinstring
└githubstring
└instagramstring
└youtubestring
└facebookstring
└contactNameNullwert zulässigstring
└contactEmailNullwert zulässigstring
└galleryarray<string>
└productIdstring
└domainstring
└thumbnailUrlNullwert zulässigstring
└completenessinteger (0–100)
└missingarray<string>
└createdAtstring
└updatedAtstring
└sitesarray<object>
└siteIdstring
└domainstring
└syncedThroughNullwert zulässigstring
Mögliche Fehler
400invalid_product_input oder invalid_url
401Authentifizierung fehlgeschlagen
403plan_required oder bei Schreibvorgängen missing_scope_publish
404product_not_found
409gallery_full
413image_too_large
415image_type
429rate_limited — 120 Anfragen pro Minute und Schlüssel
502image_unreachable
503storage_unavailable

Beispiel

bash
curl -X POST https://www.querywin.com/api/v1/products/{id}/images/from-url \
  -H "Authorization: Bearer $QUERYWIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/logo.png",
    "kind": "thumbnail"
  }'
json – Antwort
{
  "success": true,
  "data": {
    "name": "string",
    "url": "string",
    "primaryLanguage": "en",
    "businessType": "saas",
    "launchStatus": "live",
    "pricingModel": "free",
    "tagline": null,
    "shortDesc": null,
    "longDesc": null,
    "firstComment": null,
    "topics": [
      "string"
    ],
    "promoCode": "string",
    "videoUrl": "string",
    "demoUrl": "string",
    "links": {
      "webApp": "string",
      "appStore": "string",
      "playStore": "string",
      "chromeExtension": "string",
      "macos": "string",
      "windows": "string"
    },
    "socials": {
      "x": "string",
      "linkedin": "string",
      "github": "string",
      "instagram": "string",
      "youtube": "string",
      "facebook": "string"
    },
    "contactName": "string",
    "contactEmail": "string",
    "gallery": [
      "string"
    ],
    "productId": "string",
    "domain": "string",
    "thumbnailUrl": "string",
    "completeness": 0,
    "missing": [
      "string"
    ],
    "createdAt": "2026-09-01T00:00:00.000Z",
    "updatedAt": "2026-09-01T00:00:00.000Z",
    "sites": [
      {
        "siteId": "string",
        "domain": "string",
        "syncedThrough": "string"
      }
    ]
  }
}
GET/v1/tasks

Aufgaben über mehrere Kampagnen hinweg

Das Einreichungsprotokoll, nach der neuesten Aktivität sortiert. Filtere nach Produkt, Kampagne oder einer durch Kommas getrennten Statusliste. byStatus zählt jede Aufgabe im Bereich, bevor der Statusfilter angewendet wird. Kostenlos.

Abfrageparameter

FeldTypBeschreibung
productIdstringNur die Aufgaben dieses Produkts.
campaignIdstring
statusstringDurch Kommas getrennt, zum Beispiel prepared,in_progress.
pageintegerStandardwert ist 1.
pageSizeintegerStandardwert ist 30.

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataTaskList
└itemsarray<Task>
└taskIdstring
└campaignIdstring
└productIdstring
└statusenumpublished ist das, was du gemeldet hast. verified ist das, was QueryWin auf der Eintragsseite gesehen hat (ein Link bei Verzeichnissen und KI-Tool-Listen, eine Erwähnung an anderer Stelle). Halte beides in deinen Berichten getrennt.Werte: plannedpreparedin_progressblockedsubmittedpublishedverifiedfailedskipped
└blockedReasonNullwert zulässigenumWerte: logincaptchapaymentmissing_materialothernull
└missingarray<string>Erforderliche Inhalte, die im Produktprofil fehlen. Ergänze das Profil im Dashboard; die Aufgabe bereitet sich selbst erneut vor.
└listingUrlNullwert zulässigstring
└markedByenumWer die letzte Statusänderung vorgenommen hat: eine Person (oder diese API), die Browser-Erweiterung oder QueryWin selbst.Werte: userdevicesystem
└hasGeneratedbooleanEine kanalspezifische Überarbeitung ist vorhanden.
└reviewDueAtNullwert zulässigstringZeitpunkt für die nächste Prüfung nach der Einreichung (submittedAt + die Prüftage des Kanals).
└submittedAtNullwert zulässigstring
└publishedAtNullwert zulässigstring
└verifiedAtNullwert zulässigstring
└nextarray<string>Status, die du über POST /v1/tasks/{id}/status aus dem aktuellen Status setzen kannst.
└targetobject
└targetIdstring
└namestring
└urlstring
└submitUrlstring
└kindstring
└sourceenumWerte: seeduserrivals
└languagestring
└requiresBacklinkboolean
└checkNullwert zulässigobjectDie erneute Prüfung, die QueryWin nach der Veröffentlichung auf dem Eintrag durchführt. Bis zur Veröffentlichung der Aufgabe null.
└kindenumWonach gesucht wird: ein Link zum Produkt (Verzeichnisse, KI-Tool-Listen) oder eine Erwähnung der Marke (alles andere).Werte: link_livemention_seen
└stateNullwert zulässigenumconfirmed = gefunden. unconfirmed = in einer Prüfrunde nicht gefunden (Status bleibt unverändert; prüfe die URL). lost = war vorhanden und ist verschwunden (Aufgabe fehlgeschlagen).Werte: confirmedunconfirmedlostnull
└checkedAtNullwert zulässigstring
└dueAtNullwert zulässigstring
└updatedAtstring
└totalinteger
└pageinteger
└pageSizeinteger
└byStatusobject
Mögliche Fehler
401Authentifizierung fehlgeschlagen

Beispiel

bash
curl "https://www.querywin.com/api/v1/tasks" \
  -H "Authorization: Bearer $QUERYWIN_API_KEY"
json – Antwort
{
  "success": true,
  "data": {
    "items": [
      {
        "taskId": "string",
        "campaignId": "string",
        "productId": "string",
        "status": "planned",
        "blockedReason": "login",
        "missing": [
          "string"
        ],
        "listingUrl": "string",
        "markedBy": "user",
        "hasGenerated": true,
        "reviewDueAt": "2026-09-01T00:00:00.000Z",
        "submittedAt": "2026-09-01T00:00:00.000Z",
        "publishedAt": "2026-09-01T00:00:00.000Z",
        "verifiedAt": "2026-09-01T00:00:00.000Z",
        "next": [
          "string"
        ],
        "target": {
          "targetId": "string",
          "name": "string",
          "url": "string",
          "submitUrl": "string",
          "kind": "string",
          "source": "seed",
          "language": "string",
          "requiresBacklink": true
        },
        "check": {
          "kind": "link_live",
          "state": "confirmed",
          "checkedAt": "2026-09-01T00:00:00.000Z",
          "dueAt": "2026-09-01T00:00:00.000Z"
        },
        "updatedAt": "2026-09-01T00:00:00.000Z"
      }
    ],
    "total": 0,
    "page": 0,
    "pageSize": 0,
    "byStatus": null
  }
}
GET/v1/tasks/{id}

Eine Aufgabe mit dem einzureichenden Material

Jedes Feld, das das Formular des Kanals verlangt, aus dem Produktprofil gemäß den Kanalgrenzen übernommen (source: "profile"), ergänzt um die kanalspezifische Überarbeitung, falls vorhanden (source: "ai"), und um Änderungen im Dashboard (source: "override"). source: "none" bedeutet, dass das Profil für dieses Feld keine Angaben enthält — erfinde nichts. Es wird keine Überarbeitung ausgelöst und es entstehen keine Kosten.

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataTaskDetailResult
└taskTaskDetail
Mögliche Fehler
401Authentifizierung fehlgeschlagen
404task_not_found

Beispiel

bash
curl "https://www.querywin.com/api/v1/tasks/{id}" \
  -H "Authorization: Bearer $QUERYWIN_API_KEY"
json – Antwort
{
  "success": true,
  "data": {
    "task": null
  }
}
POST/v1/tasks/{id}/materials

Das Material für diesen Kanal überarbeiten (kostet Credits)

Ein KI-Durchlauf passt das Profil an diesen bestimmten Kanal an: eine kürzere Verzeichnisbeschreibung, den ersten Kommentar eines Machers, einen Community-Beitrag, einen Pitch an eine Redaktion oder — bei durch KI zitierten Websites — einen Pitch plus einen Absatz, den der Seitenbetreiber hinzufügen könnte. Synchron, innerhalb weniger Sekunden. Es werden nur Fakten aus dem Profil verwendet; jeder Teil mit einem Link, der nicht im Profil steht, wird verworfen und nicht berechnet.

Identische Eingaben liefern die vorherige Version ohne Berechnung (cached: true); force: true überarbeitet trotzdem und wird berechnet. Das Profilmaterial aus GET /v1/tasks/{id} reicht für Verzeichnisse normalerweise aus; überarbeite es, wenn der Kanal einen anderen Schreibstil verlangt.

Wenn die Validierung nichts übrig lässt, wird HTTP 200 mit ok: false und failure: "engine_failed" zurückgegeben. Nicht ausreichende Credits führen tatsächlich zu 402.

Anfragetext

FeldTypBeschreibung
confirmSpenderforderlichintegerAutorisierungsgrenze in Credits, mit derselben Bedeutung wie bei Gliederungen und Entwürfen. Lies den Preis über GET /v1/usage (materials.pricePerTask) aus. Auch erforderlich, wenn noch ein kostenloses Kontingent verfügbar ist. (min 0)
forcebooleanAuch dann überarbeiten, wenn sich seit der letzten Version nichts geändert hat. Wird berechnet.

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataWriteMaterialsOutcome
└okboolean
└failureenumVorhanden, wenn ok false ist. Es wird nichts berechnet.Werte: engine_failedengine_unavailable
└cachedbooleanDie Eingaben waren unverändert; die vorherige Version wurde zurückgegeben und es wurde nichts berechnet.
└freeUsedboolean
└creditsSpentinteger
└taskTaskDetail
Mögliche Fehler
400confirm_spend_required oder confirm_spend_too_low (der Body enthält den aktuellen price)
401Authentifizierung fehlgeschlagen
402insufficient_credits — der Body enthält requiredCredits, currentBalance, shortfall
403missing_scope_spend — diesem Schlüssel wurde der spend-Scope nicht gewährt
404task_not_found
429rate_limited oder daily_limit_reached (der Body enthält resetAt)

Beispiel

bash
curl -X POST https://www.querywin.com/api/v1/tasks/{id}/materials \
  -H "Authorization: Bearer $QUERYWIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "confirmSpend": 10
  }'
json – Antwort
{
  "success": true,
  "data": {
    "ok": true,
    "failure": "engine_failed",
    "cached": true,
    "freeUsed": true,
    "creditsSpent": 0,
    "task": null
  }
}
POST/v1/tasks/{id}/status

Das Ergebnis der Einreichung melden

Dokumentiere das Ergebnis einer Einreichung, die du mit deinen eigenen Konten vorgenommen hast. QueryWin reicht selbst nirgendwo etwas ein. Setze submitted, sobald das Formular abgeschickt wurde, und anschließend published mit der Listing-URL (dem Eintrag oder Beitrag selbst, nicht der Startseite der Website), sobald er live ist. QueryWin prüft diese Seite etwa 72 Stunden später erneut auf einen Link zu deinem Produkt (Verzeichnisse, KI-Tool-Listen) oder eine Erwähnung (alles andere) und setzt verified selbst — du kannst diesen Status nicht setzen.

blocked bedeutet „Eine Person wird benötigt“: Übergib reason (login, captcha, payment, missing_material, other). failed / skipped schließen die Aufgabe; prepared setzt sie zurück. Übergänge, die die Zustandsmaschine nicht erlaubt, sind **409 transition_not_allowed**; das Feld next der Aufgabe führt auf, was vom aktuellen Status aus zulässig ist.

Anfragetext

FeldTypBeschreibung
statuserforderlichenumverified kann nicht gesetzt werden; QueryWin setzt diesen Status nach der erneuten Prüfung des Eintrags.Werte: preparedin_progressblockedsubmittedpublishedfailedskipped
listingUrlstringFür published erforderlich: der Live-Eintrag oder -Beitrag, nicht die Startseite der Website. Nur http/https. Bei submitted optional, wenn du die URL bereits kennst.
notestring
reasonenumFür blocked erforderlich.Werte: logincaptchapaymentmissing_materialother

Antwort200

FeldTypBeschreibung
successenumWerte: true
dataTaskDetailResult
└taskTaskDetail
Mögliche Fehler
400invalid_status, listing_url_required (published benötigt listingUrl), invalid_listing_url oder reason_required (blocked benötigt reason)
401Authentifizierung fehlgeschlagen
403missing_scope_publish — diesem Schlüssel wurde der publish-Scope nicht gewährt
404task_not_found
409transition_not_allowed — lies die Aufgabe; next führt die zulässigen Status auf

Beispiel

bash
curl -X POST https://www.querywin.com/api/v1/tasks/{id}/status \
  -H "Authorization: Bearer $QUERYWIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "published",
    "listingUrl": "https://example-directory.com/tools/your-product"
  }'
json – Antwort
{
  "success": true,
  "data": {
    "task": null
  }
}
QueryWin API – Content- und Verbreitungspipelines für Skripte und KI-Agenten