{"openapi":"3.0.0","paths":{"/api/auth/password-reset/request":{"post":{"description":"Schickt einen einmaligen Link an die angegebene Adresse. Die Antwort ist immer dieselbe — auch wenn es die Adresse nicht gibt, damit dieser Endpunkt keine Auskunft darüber gibt, wer Kunde ist.","operationId":"requestPasswordReset","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestPasswordResetDto"}}}},"responses":{"200":{"description":""}},"summary":"Passwort zurücksetzen anfordern","tags":["Zugang"]}},"/api/auth/password-reset/confirm":{"post":{"description":"Setzt das Passwort über den Link aus der E-Mail. Der Link funktioniert nur einmal, und alle bestehenden Sitzungen werden beendet.","operationId":"confirmPasswordReset","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmPasswordResetDto"}}}},"responses":{"200":{"description":""}},"summary":"Neues Passwort setzen","tags":["Zugang"]}},"/api/auth/sso/exchange":{"post":{"description":"Die Auth-App löst hier den 60-Sekunden-Code aus dem SSO-Callback ein und erhält genau einmal Sitzungs-Token und Nutzer. Ein zweiter Versuch mit demselben Code schlägt fehl.","operationId":"exchangeSsoCode","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeDto"}}}},"responses":{"200":{"description":""}},"summary":"SSO-Einmal-Code gegen eine Sitzung tauschen","tags":["Zugang"]}},"/api/auth/verify-email":{"post":{"description":"Löst den Link aus der Bestätigungsmail ein. Der Link funktioniert genau einmal und gilt 48 Stunden. Ab diesem Moment werden auch die bis dahin zurückgehaltenen Conversions an die Werbeplattformen weitergegeben — nichts davon ist verloren gegangen.","operationId":"verifyEmail","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyEmailDto"}}}},"responses":{"200":{"description":""}},"summary":"E-Mail-Adresse bestätigen","tags":["Zugang"]}},"/api/auth/verify-email/resend":{"post":{"description":"Schickt dem angemeldeten Nutzer eine neue Bestätigungsmail und entwertet den vorherigen Link. Höchstens dreimal pro Stunde. Ist die Adresse bereits bestätigt, passiert nichts — das ist kein Fehler.","operationId":"resendVerificationEmail","parameters":[],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Bestätigungsmail erneut schicken","tags":["Zugang"]}},"/api/shops":{"get":{"description":"Alle Shops, auf die der angemeldete Zugang Zugriff hat, mit Kennung, Name und Shop-System. Der erste Aufruf für alles Weitere — jede andere Abfrage braucht eine dieser Shop-Kennungen.","operationId":"listShops","parameters":[],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Shops der Organisation auflisten","tags":["Shops"]}},"/api/shops/{shopId}/health":{"get":{"description":"Die Antwort auf „ist gerade etwas kaputt?“ — offene Störungen des Wächters, der letzte Prüflauf und wann das letzte Event ankam. Ein Tracking-Ausfall ist still: Die Seite läuft weiter, nur die Messung nicht.","operationId":"getShopTrackingHealth","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Läuft das Tracking sauber?","tags":["Shops"]}},"/api/shops/{shopId}/kpis":{"get":{"description":"Events der letzten 24 Stunden, Käufe und Umsatz der letzten 7 Tage sowie die Zustellquote an die Werbeplattformen. Die schnellste Antwort auf „läuft das Tracking?“.","operationId":"getShopKpis","parameters":[{"name":"shopId","required":true,"in":"path","description":"Kennung des Shops, z. B. shop_meinshop_de_ab12cd","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Kennzahlen eines Shops","tags":["Auswertung"]}},"/api/shops/{shopId}/daily":{"get":{"description":"Zeitreihe der empfangenen Events. Zeigt Einbrüche und Ausreißer auf einen Blick.","operationId":"getShopDailySeries","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}},{"name":"days","required":false,"in":"query","description":"Anzahl Tage rückwärts (Standard 14).","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Events pro Tag","tags":["Auswertung"]}},"/api/shops/{shopId}/channels":{"get":{"description":"Woher die Besucher kommen — Google Ads, Meta, organische Suche, Verweise, direkt — mit Events, Käufen und Umsatz je Kanal.","operationId":"getShopChannels","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}},{"name":"days","required":false,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Aktivste Kanäle","tags":["Auswertung"]}},"/api/shops/{shopId}/pages":{"get":{"description":"Meistbesuchte Seiten mit den Käufen und dem Umsatz, die auf ihnen entstanden sind.","operationId":"getShopTopPages","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}},{"name":"days","required":false,"in":"query","schema":{"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Beste Seiten","tags":["Auswertung"]}},"/api/shops/{shopId}/funnel":{"get":{"description":"Wie viele Besucher von der Produktansicht über den Warenkorb bis zum Kauf kommen — und wo die meisten abspringen.","operationId":"getShopFunnel","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}},{"name":"days","required":false,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Kauftrichter","tags":["Auswertung"]}},"/api/shops/{shopId}/event-types":{"get":{"description":"Wie oft jede Event-Art vorkam. Nützlich, um zu sehen, ob ein Event-Typ ganz fehlt — etwa weil ein Hook im Shop nicht greift.","operationId":"getShopEventTypes","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}},{"name":"days","required":false,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Events nach Art","tags":["Auswertung"]}},"/api/shops/{shopId}/onboarding":{"get":{"description":"Welche Schritte erledigt sind, welcher als Nächstes dran ist und was jeder bringt. Beantwortet „wo steht dieser Shop gerade?“.","operationId":"getShopOnboarding","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Stand der Einrichtung","tags":["Einrichtung"]}},"/api/shops/{shopId}/import/credentials":{"post":{"description":"Speichert Schlüssel und Geheimnis verschlüsselt und probiert sie sofort aus. Leserechte genügen — Trackdolphin schreibt nichts in den Shop. Die Werte werden nie wieder ausgeliefert.","operationId":"saveShopCredentials","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialsDto"}}}},"responses":{"201":{"description":""}},"security":[{"session":[]}],"summary":"Zugangsdaten zum Shop-System hinterlegen","tags":["Historienimport"]}},"/api/shops/{shopId}/import":{"post":{"description":"Holt die Bestellhistorie aus dem Shop-System nach und vergleicht sie mit dem, was das Tracking selbst gemeldet hat. Ergebnis ist die Erkennungsquote: wie viele Bestellungen bisher fehlten und wie viel Umsatz ohne Zuordnung blieb.","operationId":"startShopImport","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartImportDto"}}}},"responses":{"201":{"description":""}},"security":[{"session":[]}],"summary":"Historienimport starten","tags":["Historienimport"]},"get":{"description":"Läuft gerade ein Import, wie liefen die letzten, und wie viele Bestellungen hat das bisherige Tracking übersehen.","operationId":"getShopImportStatus","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Stand des Imports und Erkennungsquote","tags":["Historienimport"]}},"/api/keys":{"get":{"description":"Alle gültigen Schlüssel der Organisation mit Name, Präfix und letzter Nutzung. Der Schlüssel selbst ist nicht dabei — er wird nur bei der Erstellung gezeigt.","operationId":"listApiKeys","parameters":[],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"API-Schlüssel auflisten","tags":["API-Schlüssel"]},"post":{"description":"Erzeugt einen Schlüssel für Zugriffe ohne Browser (MCP-Server, Kommandozeile, eigene Skripte). Der Klartext wird EINMAL zurückgegeben und ist danach nicht mehr abrufbar — auch nicht für uns.","operationId":"createApiKey","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyDto"}}}},"responses":{"201":{"description":""}},"security":[{"session":[]}],"summary":"API-Schlüssel erstellen","tags":["API-Schlüssel"]}},"/api/keys/{id}":{"delete":{"description":"Macht den Schlüssel sofort ungültig. Der Eintrag bleibt als Spur erhalten.","operationId":"revokeApiKey","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"API-Schlüssel widerrufen","tags":["API-Schlüssel"]}},"/api/shops/{shopId}/routing":{"get":{"description":"Die aktuellen Regeln, die Voreinstellungen mit Begründung und die tatsächlich eingetroffenen Event-Arten der letzten 30 Tage. Letztere sind wichtig, weil eigene Events als freier Text ankommen — ein Tippfehler erzeugt sonst lautlos eine neue Art.","operationId":"getEventRouting","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Welche Events gehen an welches Ziel","tags":["Event-Routing"]},"put":{"description":"Ersetzt die Regeln des Shops. Gespeichert werden nur Abweichungen von der Voreinstellung — ein Shop ohne Regeln trackt nach den Standardwerten.","operationId":"saveEventRouting","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveRoutingDto"}}}},"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Routing-Regeln speichern","tags":["Event-Routing"]}},"/api/shops/{shopId}/environments":{"get":{"description":"Welche Umgebungen (production, staging, …) in den letzten 30 Tagen Events geschickt haben, mit Zählern. production steht immer zuerst — auch ohne Events, damit die Antwort nie leer wirkt, wenn nur noch nichts ankam. Auswertungen und Zustellung sehen ausschließlich production; alles andere wird gespeichert, aber nie gezählt oder an Werbeplattformen gemeldet.","operationId":"listShopEnvironments","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Gesehene Umgebungen eines Shops","tags":["Einrichtung"]}},"/api/detect-platform":{"post":{"description":"Ruft die Startseite und ein paar bekannte Pfade ab und schließt daraus auf das Shop-System (WooCommerce, Shopware, Shopify, Magento, PrestaShop, OXID). Nennt die Belege im Klartext. Bei zu wenigen eindeutigen Merkmalen lautet die Antwort „unbekannt“ — ein falsch geratenes System schickt den Kunden in die falsche Anleitung.","operationId":"detectShopPlatform","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetectPlatformDto"}}}},"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Shop-System an der Adresse erkennen","tags":["Einrichtung"]}},"/api/shops/{shopId}/detect-platform":{"post":{"description":"Wie detectShopPlatform, prüft aber die hinterlegte Domain des Shops und speichert ein eindeutiges Ergebnis direkt am Shop. Bei unklarem Befund wird nichts geändert — lieber weiter fragen als falsch raten.","operationId":"detectAndSaveShopPlatform","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Shop-System erkennen und übernehmen","tags":["Einrichtung"]}},"/api/shop-suggest":{"get":{"description":"Durchsucht das öffentliche Shop-Verzeichnis (Domain, Favicon, Shopsystem, Headless-Befund, Tag Manager, Pixel, Consent-Tool) während des Tippens. Sieht die Eingabe wie eine vollständige Domain aus und ist unbekannt, wird die Seite live geprüft und aufgenommen.","operationId":"suggestShops","parameters":[],"responses":{"200":{"description":""}},"summary":"Tippvorschläge für die Shop-Adresse","tags":["Verzeichnis"]}},"/api/shop-suggest/record":{"post":{"operationId":"recordShopEntry","parameters":[],"responses":{"202":{"description":""}},"summary":"Im Signup eingegebene Shop-Adresse ins Verzeichnis aufnehmen","tags":["Verzeichnis"]}},"/api/billing":{"get":{"description":"Aktueller Tarif, seine Grenzen und die Nutzung des laufenden Kalendermonats. Gezählt wird beim Empfang, nicht je Zielplattform; Historienimport und Stornos zählen nie gegen das Kontingent. Zustand: ok, warnung (ab 80 %) oder überschritten.","operationId":"getBillingStatus","parameters":[],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Tarif und Nutzung der Organisation","tags":["Tarif"]}},"/api/billing/checkout":{"post":{"description":"Erzeugt eine Stripe-Checkout-Sitzung für „shop“ oder „agentur“ und liefert die Bezahl-URL. Ist Stripe noch nicht eingerichtet, kommt eine ehrliche Meldung statt eines Fehlers.","operationId":"createCheckout","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutDto"}}}},"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Tarifwechsel starten","tags":["Tarif"]}},"/api/team":{"get":{"description":"Alle Mitglieder der aktuell gewählten Organisation mit Rolle und letzter Anmeldung — dazu die offenen Einladungen mit Ablaufdatum.","operationId":"listTeam","parameters":[],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Team der Organisation","tags":["Team"]}},"/api/team/invitations":{"post":{"description":"Schickt eine Einladung per E-Mail. Der Link gilt sieben Tage und funktioniert einmal. Nur Inhaber der Organisation dürfen einladen, und nur über eine echte Anmeldung — nicht per API-Schlüssel.","operationId":"inviteTeamMember","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteDto"}}}},"responses":{"201":{"description":""}},"security":[{"session":[]}],"summary":"Teammitglied einladen","tags":["Team"]}},"/api/team/invitations/{id}":{"delete":{"description":"Macht den Einladungslink sofort ungültig. Nur für Inhaber.","operationId":"revokeInvitation","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Einladung widerrufen","tags":["Team"]}},"/api/auth/invitation":{"get":{"description":"Zeigt, wer zu welcher Organisation einlädt — für die Annahme-Seite, bevor jemand Name und Passwort eintippt. Bei ungültigem Link kommt nur `valid: false`, ohne Details.","operationId":"previewInvitation","parameters":[{"name":"token","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"summary":"Einladung ansehen","tags":["Zugang"]}},"/api/auth/invitation/accept":{"post":{"description":"Legt mit Name und Passwort ein Konto in der einladenden Organisation an und meldet direkt an. Der Link funktioniert nur einmal.","operationId":"acceptInvitation","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptInvitationDto"}}}},"responses":{"200":{"description":""}},"summary":"Einladung annehmen","tags":["Zugang"]}},"/api/shops/{shopId}/pulls":{"post":{"description":"Reiht einen Abruf ein (Kampagnen, Conversion-Actions, Pixel/Datasets, GA4-Properties) und antwortet sofort. Läuft für denselben Shop und Kanal bereits einer, wird KEIN zweiter gestartet — die Antwort zeigt dann den laufenden Abruf und `enqueued: false`.","operationId":"startChannelPull","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartPullDto"}}}},"responses":{"202":{"description":""}},"security":[{"session":[]}],"summary":"Kontodaten eines Kanals im Hintergrund holen","tags":["Konto-Abrufe"]},"get":{"description":"Die Abrufe dieses Shops, neueste zuerst — Status plus eine Kurzfassung wie „3 Kampagnen, 2 Conversion-Actions“. Der Endpunkt, den Schritt 4 des Assistenten abfragt, solange noch etwas offen ist.","operationId":"listChannelPulls","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Stand der Abrufe","tags":["Konto-Abrufe"]}},"/api/shops/{shopId}/pulls/{pullId}":{"get":{"description":"Wie die Liste, zusätzlich mit `data` — den tatsächlich geholten Konten, Kampagnen, Pixeln und Properties. Damit belegt der Assistent die Ziel-Konfiguration vor, statt den Kunden Kennungen abtippen zu lassen.","operationId":"getChannelPull","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}},{"name":"pullId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Ein Abruf mit seinen Daten","tags":["Konto-Abrufe"]}},"/api/shops/{shopId}/gtm/import":{"post":{"description":"Reiht den Import ein und antwortet sofort. Ohne `container_public_id` nehmen wir die Kennung, die beim Tippen der Domain auf der Startseite gefunden wurde; gibt es auch die nicht, kommt 400. Ohne verbundenen Tag Manager kommt 409. Läuft bereits ein Import, wird KEIN zweiter gestartet — die Antwort zeigt dann den laufenden und `enqueued: false`.","operationId":"startGtmImport","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartGtmImportDto"}}}},"responses":{"202":{"description":""}},"security":[{"session":[]}],"summary":"Tag-Manager-Container lesen und auswerten","tags":["GTM-Import"]},"get":{"description":"Der letzte Import dieses Shops: Status, ein Satz für die Oberfläche und — sobald fertig — der Befund je Tag samt Empfehlung. `import` ist null, solange nie einer lief. `pending` erspart dem Frontend das Nachrechnen, ob es weiter abfragen muss.","operationId":"getGtmImport","parameters":[{"name":"shopId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"session":[]}],"summary":"Stand und Befund des letzten Imports","tags":["GTM-Import"]}},"/api/audit":{"post":{"description":"Reiht den Scan ein und antwortet sofort mit 202. Läuft für die Domain bereits ein Scan, wird KEIN zweiter gestartet — die Antwort zeigt dann den laufenden und `enqueued: false`. Dasselbe gilt für ein Ergebnis, das jünger als 24 Stunden ist: Es wird wiederverwendet, statt einen fremden Server erneut zu belasten. Danach `GET /api/audit/{id}` abfragen, bis `status` auf „done“, „failed“ oder „blocked“ steht. „blocked“ heisst: Der Shop lässt automatisierte Aufrufe nicht zu — das ist ein Ergebnis, kein Fehler, und muss dem Besucher auch so gezeigt werden. Während des Wartens tragen die Antworten `progress` (Phase, Satz, Balken, Restzeit) und ab der Hälfte `preview` (Plattform, Einwilligungswerkzeug, Tag Manager, Cookies und Tracking-Hosts vor jeder Einwilligung). Ist die Schlange voll, antwortet der Endpunkt mit 503 und `Retry-After` — ein vorhandenes Ergebnis unter 24 Stunden wird auch dann noch ausgeliefert.","operationId":"startTrackingAudit","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartAuditDto"}}}},"responses":{"202":{"description":""}},"summary":"Eine Seite auf Tracking vor der Einwilligung prüfen","tags":["Tracking-Audit"]},"get":{"description":"Der jüngste Lauf zu dieser Domain — die Grundlage für dauerhafte Report-Adressen. `audit` ist null, wenn die Domain noch nie gescannt wurde.","operationId":"getLatestTrackingAudit","parameters":[],"responses":{"200":{"description":""}},"summary":"Letzter Scan zu einer Domain","tags":["Tracking-Audit"]}},"/api/audit/{id}":{"get":{"description":"Status, ein anzeigbarer Satz und — sobald fertig — die Befunde. Die vollständige Messung wird NICHT ausgeliefert: Sie enthält Rohdaten einer fremden Website. `progress.percent` steigt monoton und steht nur bei „done“ auf 100; `progress.eta_seconds` ist null, wenn wir die Restzeit ehrlich nicht kennen. `preview` erscheint, sobald der passive Durchgang durch ist — also lange vor den Befunden. Bei „failed“ und „blocked“ bleibt der letzte Fortschritt stehen: Er zeigt, wie weit wir kamen. `robots` MUSS die Seite als Meta-Angabe setzen, `visibility` ist immer „unlisted“, und nach `retention_days` Tagen wird der Bericht automatisch gelöscht.","operationId":"getTrackingAudit","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"summary":"Stand und Befund eines Scans","tags":["Tracking-Audit"]}}},"info":{"title":"Trackdolphin API","description":"Serverseitiges Tracking für Onlineshops. Jede Fähigkeit des Produkts ist über diese API erreichbar — die Oberfläche nutzt dieselben Endpunkte.","version":"1","contact":{}},"tags":[],"servers":[],"components":{"securitySchemes":{"session":{"scheme":"bearer","bearerFormat":"JWT","type":"http","description":"Sitzungs-Token aus /api/auth/login"}},"schemas":{"RequestPasswordResetDto":{"type":"object","properties":{}},"ConfirmPasswordResetDto":{"type":"object","properties":{}},"ExchangeDto":{"type":"object","properties":{}},"VerifyEmailDto":{"type":"object","properties":{}},"SaveCredentialsDto":{"type":"object","properties":{}},"StartImportDto":{"type":"object","properties":{}},"CreateApiKeyDto":{"type":"object","properties":{}},"SaveRoutingDto":{"type":"object","properties":{}},"DetectPlatformDto":{"type":"object","properties":{}},"CheckoutDto":{"type":"object","properties":{}},"InviteDto":{"type":"object","properties":{}},"AcceptInvitationDto":{"type":"object","properties":{}},"StartPullDto":{"type":"object","properties":{}},"StartGtmImportDto":{"type":"object","properties":{}},"StartAuditDto":{"type":"object","properties":{}}}}}