Zum Inhalt
Markenfrei

API für Entwickler

Dieselbe Prüfung wie auf der Webseite, als JSON-Schnittstelle: ohne Konto, ohne Schlüssel, ohne LLM. Du schickst einen Namen oder eine Shortlist und bekommst je Name eine Zeile pro Quelle, eine Ampel und die Vorbereitung für die Markenrecherche. Suchanfragen werden nicht gespeichert.

Grün heißt nicht „frei“. „Nicht gefunden“ heißt nur, dass die Quelle den Namen nicht kennt. „Unbekannt“ ist nie frei. Die Marke wird nicht geprüft; dafür liefert die Antwort Links und eine Checkliste. Vorprüfung, keine Rechtsberatung.

Überblick

Öffentliche Endpunkte
EndpunktZweck
POST /api/checkEinen Namen oder bis zu 10 Namen prüfen
POST /api/mcpMCP über Streamable HTTP für Agenten, siehe MCP einrichten
GET /api/healthLebenszeichen für Monitoring: { "status": "ok", "version": "…" }
GET /api/openapi.jsonOpenAPI-3.1-Beschreibung dieser Schnittstelle

Die Beispiele zeigen https://markenfrei.app. Bei einer selbst betriebenen Instanz setzt du deren Adresse ein. Aufrufe aus Browserseiten fremder Herkunft werden abgelehnt (403, kein CORS); curl, Skripte und Server ohne Origin-Header funktionieren.

Grenzen und faire Nutzung

  • Gedacht für Einzelabfragen, die ein Mensch oder dein Werkzeug für ein konkretes Projekt auslöst, nicht für Massenabfragen oder das Abgrasen von Namenslisten. Jede Prüfung fragt offene Dienste Dritter ab; deren Grenzen schützen wir mit.
  • Höchstens 10 Namen pro Anfrage, Body höchstens 16 KB, höchstens 8 verschiedene Endungen, Content-Type application/json.
  • Rate-Limit pro IP: standardmäßig 60 Einheiten pro 60 Sekunden. Jeder verschiedene Name zählt eine Einheit; eine größere Quellenauswahl kostet ein Vielfaches. Danach antwortet der Server mit 429 und Retry-After. Betreiber einer eigenen Instanz können den Wert ändern. Zusätzlich gibt es ein Limit pro Serverprozess, das die abgefragten Dienste schützt.
  • Eindeutige Antworten der Quellen hält der Server 10 Minuten im Arbeitsspeicher. Dieselbe Prüfung innerhalb dieser Zeit liefert dieselben Ergebnisse und belastet die Dienste nicht erneut. Quellen ohne Antwort (unknown) werden nicht gemerkt; bei retryable: true lohnt sich ein neuer Versuch nach einigen Sekunden.
  • Eine Prüfung dauert höchstens etwa 8 Sekunden. Setze im Client ein Timeout von 15 bis 20 Sekunden.
  • unknown ist keine Antwort „frei“. Wer Ergebnisse automatisch auswertet, sollte incomplete und unknown als offen behandeln.

Beispiele

Eingabe: names (Pflicht, 1 bis 10), optional tlds, namespaces und sources. Ohne Angabe gelten die Standardwerte (siehe Werte).

curl: ein Name mit Standardauswahl
curl -s https://markenfrei.app/api/check \
  -H "Content-Type: application/json" \
  -d '{"names":["wachwerk"]}'
curl: Shortlist, nur die Rangliste anzeigen (jq)
curl -s https://markenfrei.app/api/check \
  -H "Content-Type: application/json" \
  -d '{"names":["wachwerk","fokusnova","klarwerk"]}' \
  | jq '.ranking'
curl: Endungen, Namensräume und Quellen wählen
curl -s https://markenfrei.app/api/check \
  -H "Content-Type: application/json" \
  -d '{"names":["wachwerk"],"tlds":["de","com","dev"],"namespaces":["domains","packages","social"],"sources":["npm","pypi","nuget","bluesky"]}'

sources ersetzt die Standardquellen außerhalb von Domains: Wer Zusatzquellen will, schickt die gewünschten Standardquellen mit. Domains kommen weiter aus tlds und namespaces. Im Namensraum social ist keine Quelle Standard, dort wählst du über sources.

JavaScript (fetch, Node 18 oder neuer)
const res = await fetch("https://markenfrei.app/api/check", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({"names":["wachwerk","fokusnova","klarwerk"]}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error); // 4xx und 5xx: { error: "..." }

for (const entry of data.ranking) {
  // "green" heißt nur: in den gewählten Quellen nichts gefunden
  console.log(entry.name, entry.verdict, "vergeben:", entry.taken, "unbekannt:", entry.unknown);
}
Python (requests)
import requests

res = requests.post(
    "https://markenfrei.app/api/check",
    json={"names":["wachwerk","fokusnova","klarwerk"]},
    timeout=20,
)
data = res.json()
if not res.ok:
    # 429: Retry-After nennt die Wartezeit in Sekunden
    raise SystemExit(data["error"])

for entry in data["ranking"]:
    # "green" heißt nur: in den gewählten Quellen nichts gefunden
    print(entry["name"], entry["verdict"], "vergeben:", entry["taken"], "unbekannt:", entry["unknown"])

Antwort

Die Antwort ist ein Objekt mit ranking und reports, mit Cache-Control: no-store. Das Format ist ein Vertrag (schemaVersion: 2) und in OpenAPI vollständig beschrieben.

ranking
Dieselben Namen als Rangliste: zuerst Namen ohne Treffer in allen gewählten Quellen, dann wenige Treffer, dann wenige unzulässige Namensräume, dann wenige Lücken. Enthält je Name verdict, freeInAll und die Quellen mit taken, invalid und unknown.
reports
Ein Bericht je verschiedenem Namen (nach der Normalisierung) in Eingabereihenfolge.
reports[].verdict
Ampel aus den Status aller Quellen: green, yellow oder red.
reports[].counts
Anzahl der Quellen je Status.
reports[].incomplete
Namen der Quellen ohne verwertbare Antwort. Dort heißt „nichts gefunden“ nicht „frei“.
reports[].results[]
Eine Zeile je Quelle: sourceId, namespace, label, target, status und, wo vorhanden, url zum Nachprüfen, note, evidence, weak (schwaches Signal, höchstens Gelb) und retryable (bei unknown: später erneut versuchen lohnt sich).
reports[].trademark
Vorbereitung der Markenrecherche: Registerlinks, DPMA-Expertensuchstring, Schreibvarianten, Klassenvorschlag, Checkliste. status ist immer not_checked: Marken werden nicht abgefragt.
reports[].manualLinks
Links zum Nachsehen von Hand (Instagram, TikTok, X, YouTube, Chrome Web Store). Hier wird nichts abgefragt.

Status je Quelle

taken (vergeben)
Die Quelle kennt den Namen: vergeben.
not_found (nicht gefunden)
Die Quelle kennt den Namen nicht. Das heißt nicht, dass er frei oder registrierbar ist.
similar (ähnlich)
Ähnlicher oder nicht eindeutiger Treffer.
invalid (nicht zulässig)
Der Name ist dort nicht zulässig (Syntax oder Länge). Nicht vergeben.
unknown (unbekannt)
Keine verwertbare Antwort (Zeitüberschreitung, Fehler, Abfragegrenze). Nie als frei werten.

Ampel

green (Keine Treffer)
Alle gewählten Quellen kennen den Namen nicht. Keine Freigabe und keine Aussage zur Marke.
yellow (Treffer oder Lücken prüfen)
Ähnliche oder schwache Treffer, nicht zulässig oder eine Quelle ohne Antwort: genauer ansehen.
red (Vergeben)
Mindestens eine Quelle meldet den Namen als vergeben.
Beispielantwort für {"names":["wachwerk"]} (gekürzt, Werte ausgedacht)
{
  "ranking": [
    {
      "name": "wachwerk",
      "verdict": "yellow",
      "freeInAll": false,
      "taken": [],
      "invalid": [],
      "unknown": [
        "App Store"
      ]
    }
  ],
  "reports": [
    {
      "schemaVersion": 2,
      "input": "Wachwerk",
      "name": "wachwerk",
      "checkedAt": "2026-11-05T09:30:00.000Z",
      "verdict": "yellow",
      "verdictLabel": "Treffer oder Lücken prüfen",
      "counts": {
        "taken": 0,
        "not_found": 3,
        "similar": 0,
        "invalid": 0,
        "unknown": 1
      },
      "incomplete": [
        "App Store"
      ],
      "results": [
        {
          "sourceId": "rdap:de",
          "namespace": "domains",
          "label": ".de",
          "target": "wachwerk.de",
          "status": "not_found",
          "evidence": "RDAP HTTP 404"
        },
        {
          "sourceId": "rdap:com",
          "namespace": "domains",
          "label": ".com",
          "target": "wachwerk.com",
          "status": "not_found",
          "evidence": "RDAP HTTP 404"
        },
        {
          "sourceId": "npm",
          "namespace": "packages",
          "label": "npm",
          "target": "wachwerk",
          "status": "not_found",
          "evidence": "HTTP 404",
          "url": "https://www.npmjs.com/package/wachwerk"
        },
        {
          "sourceId": "appstore",
          "namespace": "stores",
          "label": "App Store",
          "target": "wachwerk",
          "status": "unknown",
          "evidence": "timeout",
          "retryable": true
        }
      ],
      "trademark": {
        "status": "not_checked",
        "note": "Markenregister wurden nicht abgefragt. Eine leere Trefferliste hier heißt nicht, dass der Name als Marke frei ist.",
        "links": [
          {
            "office": "DPMA",
            "label": "DPMAregister Schnellsuche",
            "url": "https://register.dpma.de/DPMAregister/marke/erweitert?fromSmartSearch=true&queryString=wachwerk",
            "what": "Deutsche Marken sowie Unions- und IR-Marken mit Schutz in Deutschland. Vorausgefüllt; sucht den Begriff in Marke, Inhaber und Aktenzeichen. Keine Ähnlichkeitssuche."
          },
          {
            "office": "DPMA",
            "label": "DPMAregister Expertenrecherche",
            "url": "https://register.dpma.de/DPMAregister/marke/experte",
            "what": "Nicht vorausgefüllt: den Expertensuchstring kopieren und ins Eingabefeld einfügen. Findet Schreibvarianten über Platzhalter."
          }
        ],
        "dpmaExpertQuery": "(MARKE=?wachwerk? ODER MARKE=?wachwerc?) UND (KL=09 ODER KL=42)",
        "variants": [
          "wachwerc"
        ],
        "classes": [
          {
            "number": 9,
            "title": "Klasse 9 · Apps & herunterladbare Software",
            "reason": "Pflichtklasse für Mobile Apps (iOS/Android), Desktop-Software & KI-Modelle."
          }
        ],
        "checklist": [
          "Identische Marken suchen: den Namen im DPMAregister, in EUIPO eSearch plus und in TMview eingeben (Deutschland, EU und international registrierte Marken mit Schutz in Deutschland).",
          "Ähnliche Marken suchen: alle Schreibvarianten und klangähnliche Formen prüfen. Das DPMAregister hat keine Ähnlichkeitssuche, dafür hilft der Expertensuchstring mit Platzhaltern."
        ]
      },
      "manualLinks": [
        {
          "label": "Instagram",
          "url": "https://www.instagram.com/wachwerk/"
        },
        {
          "label": "TikTok",
          "url": "https://www.tiktok.com/@wachwerk"
        }
      ]
    }
  ]
}

Gekürzt: Die echte Antwort enthält je Name eine Zeile für jede gewählte Quelle, alle Registerlinks und die vollständige Checkliste. Die Werte im Beispiel sind ausgedacht, kein Prüfergebnis. Im Beispiel ist die Ampel gelb, weil eine Quelle nicht geantwortet hat; auch bei grün wäre der Name nicht als frei oder als Marke freigegeben zu verstehen.

Erlaubte Werte

namespaces
domains (Domains, Standard)packages (Pakete, Standard)stores (App Stores, Standard)social (Social)known_names (Bekannte Namen, Standard)
tlds
Höchstens 8 verschiedene. Standard: de, com, dev, app, io. Erlaubt: de, com, net, org, dev, app, io, ai, ch, li, fr, uk, nl, pl, cz, xyz, shop, tech, info, cloud, online, site, store, blog, design, space, biz, pro, ca, tv, berlin, at, eu. Verfahren je Endung stehen unter Quellen.
sources, Standardauswahl
npm, pypi, github, crates, homebrew, appstore, googleplay, known_brands, wikidata, gleif
sources, auf Wunsch
nuget, rubygems, maven, packagist, pub, jsr, hex, cran, openvsx, huggingface, hackage, terraform, devto, aur, repology, docker, conda, clojars, fdroid, firefox, bluesky, mastodon, hackernews, wikipedia, hn_show

Was hinter jeder Quelle steckt, steht unter Quellen. Unbekannte Werte lehnt die Schnittstelle mit 400 ab.

Fehler

Fehler kommen als { "error": "<deutsche Meldung>" } mit passendem Status. Die Meldung nennt den Grund und enthält nie interne Details.

Fehlerantworten von POST /api/check
StatusFallMeldung
400Kaputtes JSON, falsche Typen, keine oder zu viele Namen, ungültiger Name, unbekannte Endung, Quelle oder Namensraumz. B. „Höchstens 10 Namen pro Anfrage.“
403Aufruf aus einer fremden Browserseite (Origin nicht erlaubt)Aufrufe von fremden Seiten sind nicht erlaubt.
413Body größer als 16 KBDie Anfrage ist zu groß (höchstens 16 KB).
415Content-Type ist nicht application/jsonBitte als JSON senden (Content-Type: application/json).
429Rate-Limit erreicht; Retry-After nennt die SekundenZu viele Anfragen. Bitte in 12 Sekunden erneut versuchen.
500Unerwarteter FehlerDie Prüfung ist fehlgeschlagen. Bitte später erneut versuchen.

Maschinenlesbar und für Agenten

  • /api/openapi.json: OpenAPI 3.1 mit allen Schemas, Grenzen und Fehlerantworten, erzeugt aus demselben Code wie die Schnittstelle.
  • /mcp: Einrichtung des MCP-Servers für Coding-Agenten (POST /api/mcp), mit denselben Regeln: not_found und unknown sind nie frei, die Marke bleibt „nicht geprüft“.
  • Quellcode und Issues auf GitHub (MIT).