Entwicklerinnen und Entwickler
API-Dokumentation
Passion Tax bietet Tax-Tech-Plattformen eine REST-Schnittstelle. Ihre App sendet einen Request pro Nutzer; Passion Tax legt Mandant und Fall an, übergibt ihn an die zu Ihrem Schlüssel hinterlegte Kanzlei und gibt einen passwortlosen Zugangslink zurück, den Sie als Button anzeigen.
- Stand
- 14. September 2026
Inhalt
Maßgeblich ist diese Fassung. Sie beschreibt den Stand vom 14. September 2026; ältere Fassungen der Schnittstellenbeschreibung gelten nicht mehr. Änderungen kündigen wir über die angegebene Adresse an.
Übersicht
- Basis-URL
https://passion.tax- API-Version
2026-09-05- Format
- JSON über HTTPS
- Authentifizierung
- Bearer-Token (API-Schlüssel)
- Rate-Limit
- Standard 30 Anfragen / Minute pro Schlüssel, auf Anfrage bis 1.000
- Zuweisung
- Ihr Schlüssel ist an eine Kanzlei gebunden; alle Fälle gehen an diese Kanzlei, ohne Matching
- Zahlung
- Online über Passion Tax, sobald die Kanzlei bei unserem Zahlungsanbieter Mollie verifiziert und auf Live geschaltet ist — bis dahin für diese Kanzlei noch nicht möglich
- Rückmeldungen
- Signierte Callbacks; zugesagt ist nur case.assigned direkt nach dem Push
Authentifizierung
Senden Sie Ihren API-Schlüssel als Bearer-Token im Authorization-Header. Schlüssel beginnen mit ptk_, darauf folgen 64 Hex-Zeichen (68 Zeichen insgesamt). Wenden Sie sich an api@passion.tax, um einen Schlüssel zu beantragen.
Authorization: Bearer ptk_<64 hex>
Content-Type: application/jsonZusammen mit dem Schlüssel erhalten Sie einmalig ein Callback-Secret (64 Hex-Zeichen) für die Signaturprüfung Ihrer Callbacks. Beides wird nicht erneut angezeigt und bei Verlust nicht wiederhergestellt, sondern neu ausgestellt. Ein Schlüssel ist an eine Ziel-Kanzlei gebunden: alle Fälle dieses Schlüssels landen dort, ohne Matching über den Marktplatz.
Endpoint: Fall einreichen
POST/api/webhooks/intake
Request Body (minimal)
{
"produkt_code": "SP-E03",
"referenz_id": "app-user-8821-2026",
"mandant_eigenschaft": "verbraucher",
"mandant": {
"vorname": "Max",
"nachname": "Mustermann",
"email": "max.mustermann@beispiel.example"
},
"einwilligung": {
"erteilt_am": "2026-09-01T10:05:00Z",
"datenweitergabe_an_kanzlei": true,
"plattform_agb_akzeptiert": true
}
}Unbekannte Felder werden mit 400 validierung abgelehnt, damit Tippfehler sofort auffallen. Ausgenommen sind die Zeilen in strukturdaten.transaktionen[] und hardware[] — dort sind eigene Zusatzfelder erlaubt und werden unverändert gespeichert.
Felder
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| mandant.vorname | string ≤100 | ja | Vorname des Mandanten |
| mandant.nachname | string ≤100 | ja | Nachname des Mandanten |
| mandant.email | ja | Login-Identität des Mandanten. Ein bestehendes Mandantenkonto wird wiedererkannt und der Fall daran angehängt; vorhandene Stammdaten werden nicht überschrieben, nur Lücken ergänzt — die 201-Antwort zeigt das (siehe Antwort und Zugangslink). Gehört die Adresse zu einem Berater- oder Admin-Konto: 409 konto_konflikt. | |
| mandant_eigenschaft | verbraucher · unternehmer | ja | Einstufung dieses VORGANGS, nicht der Person — bewusst je Vorgang setzen, nicht pauschal je Nutzer: eine private Steuererklärung ist verbraucher, auch wenn der Nutzer ein Gewerbe betreibt. Bei verbraucher nimmt der Mandant den Kostenvoranschlag nur mit Zustimmung zur Widerrufsbelehrung an. Nach dem Versand des Kostenvoranschlags ist die Einstufung nicht mehr änderbar (mit angebot.automatisch also ab dem Push); die Schnittstelle bietet keinen Weg, sie zu ändern. Keine Ableitung aus mandant.typ. |
| einwilligung | Objekt | ja | erteilt_am (ISO-8601 mit Zeitzone), datenweitergabe_an_kanzlei: true, plattform_agb_akzeptiert: true; optional text_version, quelle und ip. Wird als Nachweis protokolliert (Art. 30 DSGVO). |
| produkt_code | string | bedingt | Standardprodukt, z. B. SP-E03. Pflicht, wenn sachverhalt fehlt. Unbekannt oder inaktiv: 422 produkt_unbekannt — es wird nichts stillschweigend geraten. |
| sachverhalt | string 20–20.000 | bedingt | Freitext des Anliegens. Pflicht, wenn produkt_code fehlt. Bei kanzleigebundenen Schlüsseln läuft ohne produkt_code keine KI-Klassifikation. |
| referenz_id | string ≤255 | dringend empfohlen | Ihre stabile Kennung des Vorgangs — Grundlage der Idempotenz, der Callbacks und des Zugangslink-Endpoints. |
| callback_url | URL | nein | Ziel für Status-Callbacks. Nur https; der Host wird vor jedem Zustellversuch per DNS geprüft. Eine unbrauchbare callback_url lehnt den Request nicht ab: zeigt der Host auf eine interne Adresse oder ist die URL strukturell unzulässig, wird sie verworfen und es werden für diesen Fall keine Callbacks zugestellt — der Grund steht in warnungen. Löst sie nur derzeit nicht auf, wird sie gespeichert und die Retry-Kette läuft an. Weiterleitungen werden bei der Zustellung nicht verfolgt: eine URL, die mit 3xx umleitet, wird nie beliefert. |
| kanzlei_slug | string | nein | Redundanz-Check: muss zur Kanzlei des Schlüssels passen, sonst 403 kanzlei_mismatch. |
| kyc | Objekt | nein | Übernahme eines bei Ihnen bestandenen KYC: anbieter, externe_id, verifiziert_am, verfahren, dokumentart, dokument_gueltig_bis. Ohne diesen Block erscheint der Mandant beim Berater als „nicht identifiziert“. Der übernommene Identitätsnachweis ist append-only und lässt sich nicht löschen — nur für echte Personen und bestandene Prüfungen senden. |
| dokumente | Array ≤10 | nein | Je Eintrag name, mime_type und entweder inhalt_base64 oder url (https, wird ohne Weiterleitungen geladen). Max. 15 MB je Datei und 40 MB entpackt über alle Dokumente zusammen; beide Wege zählen in dieselbe Summe (siehe Grenzen und Last). Der Inhalt wird gegen den deklarierten mime_type geprüft. |
| strukturdaten | Objekt | nein | transaktionen[] (max. 50.000) und hardware[] (max. 500). Deterministisch gespeichert, nicht durch KI verarbeitet; Zusatzfelder je Zeile sind erlaubt. Zahlen sind auf 15–17 signifikante Stellen begrenzt (IEEE-754) — Basiseinheiten wie wei als String in einem Zusatzfeld schicken. |
| angebot.automatisch | boolean | nein | true: Der Festpreis des Produkts wird sofort als offener Kostenvoranschlag am Fall hinterlegt und gilt damit als versandt. Nur bei Festpreis-Produkten wirksam. Vor der Annahme bestätigt der Mandant einmalig sein vorausgefülltes Personenprofil — steht das noch aus, weist die Antwort in warnungen darauf hin. Online bezahlen kann der Mandant erst, wenn die Kanzlei bei Mollie verifiziert und auf Live geschaltet ist (siehe Nach dem Push). |
| mandant.* | diverse | nein | Weitere Stammdaten: externe_id, anrede, titel, telefon, typ, geburtsdatum, staatsangehoerigkeit, adresse, bank, steuer_id, steuernummer, finanzamt, familienstand, kinder, krankenversicherung, religion. |
Grenzen und Last
| Grenze je Push | Wert | bei Überschreitung |
|---|---|---|
| Dokumente | 10 | 400 validierung |
| Datei | 15 MB | Base64: 413 dokument_zu_gross; per url: das Dokument kommt mit status: "fehler" zurück |
| Dokumente zusammen (entpackt) | 40 MB | Base64: 413 dokument_zu_gross; beim Nachladen per url: die restlichen Dokumente mit fehler |
| Request-Body | 45 MB | 413 des vorgeschalteten Proxys, als HTML ohne JSON-Körper |
| strukturdaten.transaktionen[] | 50.000 Zeilen | 400 validierung — größere Bestände als CSV-Dokument |
| strukturdaten.hardware[] | 500 Zeilen | 400 validierung |
Rate-Limit: Standard 30 Anfragen pro Minute je Schlüssel, auf Anfrage bis 1.000. Es zählt jeder Request mit gültigem Schlüssel, auch Trockenläufe und der Zugangslink-Endpoint. Bei 429 nach Retry-After Sekunden mit derselben referenz_id wiederholen.
Senden Sie Pushes über eine Warteschlange mit Wiederholung (siehe Fehler und Wiederholung): so bleibt ein Ansturm unter dem Limit, und ein Fehler geht nicht verloren. Große Pushes (viele Dokumente, zehntausende Transaktionen) höchstens 2–4 gleichzeitig je Schlüssel. Dokumente per url werden nacheinander geladen, mit bis zu 20 Sekunden je Datei — setzen Sie den Client-Timeout auf mindestens 130 Sekunden.
Dry-Run
POST/api/webhooks/intake?dry_run=1
Der Trockenlauf prüft den kompletten Request, das Produkt und die Ziel-Kanzlei und antwortet 200 mit einer Vorschau — ohne etwas anzulegen: kein Konto, kein Fall, keine Mail. Einziger Schreibvorgang ist ein Eintrag im Intake-Protokoll. Alternativ per Kopfzeile X-Dry-Run: 1.
{
"dry_run": true,
"gueltig": true,
"blockierend": [],
"api_version": "2026-09-05",
"kanzlei": { "id": "…", "name": "Muster Steuerberatung", "slug": "muster" },
"zuweisung": { "modus": "kanzlei_pin", "regel": "round_robin" },
"produkt": { "code": "SP-E03", "name": "Krypto-Steuerberatung", "festpreis_netto": 490, "festpreis_brutto": 583.1 },
"angebot_automatisch": true,
"umfang": { "kyc": true, "dokumente": 2, "transaktionen": 1, "hardware": 1, "einwilligung": true },
"hinweise": []
}Werten Sie gueltig und blockierend aus: gueltig ist false, wenn der echte Push sicher scheitern würde, und blockierend nennt dann den Code, den Sie bekämen — derzeit nur konto_konflikt (die E-Mail gehört zu einem Berater- oder Admin-Konto). hinweise ist Fließtext: dort steht, was der echte Push anders machen würde, ohne zu scheitern — etwa ein fehlender kyc-Block, eine callback_url oder Dokument-url, deren Host nicht auflöst oder nach innen zeigt, oder ein mime_type, den der Dokumentenspeicher nicht annimmt.
Ob zu einer E-Mail-Adresse schon ein Mandantenkonto besteht, sagt der Trockenlauf nicht. Der echte Push zeigt es (siehe Antwort und Zugangslink).
Die Flagge ist fail-closed: jede gesetzte Flagge gilt als Trockenlauf. Nur dry_run=0 bzw. false schaltet den echten Push frei, und ein nicht erkannter Wert kommt als Hinweis zurück. Ein Push ohne die Flagge erzeugt einen echten Mandanten und Fall bei der Kanzlei — und für Partner-Fälle gibt es keinen Löschweg.
Antwort und Zugangslink
201 Created
{
"success": true,
"api_version": "2026-09-05",
"fall_id": "cd20024c-03c2-40b5-9226-3ec76480021f",
"fall_nummer": "TT-2026-0142",
"status": "zugewiesen",
"mandant_id": "6b1f…",
"steuerberater": { "name": "Maria Muster", "fachgebiet": "einkommensteuer" },
"kanzlei": { "id": "…", "name": "Muster Steuerberatung", "slug": "muster" },
"produkt_code": "SP-E03",
"kyc": { "public_kyc_id": "PT-P-7K3M-…", "uebernommen": true },
"dokumente": [{ "name": "Ausweis.pdf", "status": "gespeichert", "id": "…" }],
"strukturdaten": [{ "typ": "krypto_transaktionen", "zeilen": 1, "status": "gespeichert" }],
"angebot": { "status": "offen", "preis_netto": 490, "preis_brutto": 583.1 },
"mandant_access_url": "https://passion.tax/zugang/8f3K…",
"mandant_access_expires_at": "2026-09-19T12:00:00.000Z",
"mandant_login_url": "https://passion.tax/login",
"warnungen": []
}mandant_access_url ist der passwortlose Zugangslink: er meldet den Nutzer an und öffnet den Fall. Zeigen Sie ihn als Button („Vorgang beim Steuerberater öffnen“). 14 Tage gültig, bis zu zehnmal nutzbar. Behandeln Sie ihn wie ein Passwort — nur dem jeweiligen Nutzer anzeigen, nicht loggen. Denselben Link bekommt der Nutzer per Mail.
Bestehendes Konto. Existiert zur E-Mail schon ein Mandantenkonto, wird der Fall daran angehängt, und die Antwort zeigt das. warnungen enthält „Bestehendes Mandantenkonto: Stammdaten nur ergänzt, nicht überschrieben.“, sobald zu dem Konto ein Mandantenprofil besteht; mandant_id ist dann dessen ID. Stammt das Konto nicht aus Ihrer App, ist mandant_access_url null — dann erhält nur der Kontoinhaber den Link per Mail, als Schutz vor Kontoübernahme —, und warnungen enthält „Bestehendes Konto: Zugangslink nur per E-Mail an den Mandanten gesendet, nicht an den Partner zurückgegeben.“ Ein echter Push verrät also, ob zu einer Adresse ein Konto besteht; senden Sie ihn nur für Nutzer, die der Übermittlung zugestimmt haben.
Lesen und protokollieren Sie warnungen immer: dort stehen nicht-fatale Abweichungen, etwa ein nicht gespeichertes Dokument oder eine Zugangs-Mail, die nicht zugestellt werden konnte. Ein Temporärpasswort gibt es seit v2 nicht mehr; das v1-Feld mandant_temporary_password entfällt ersatzlos.
Zugangslink erneuern
POST/api/webhooks/intake/zugang
{ "referenz_id": "app-user-8821-2026" }Alternativ { "fall_id": "…" }. Die Antwort enthält mandant_access_url, mandant_access_expires_at und per_email_gesendet. Nur für Fälle, die mit genau diesem Schlüssel angelegt wurden — sonst, auch für Fälle eines früheren, rotierten Schlüssels, 404 fall_nicht_gefunden. Eine Neuausstellung macht alle früheren Links dieses Falls ungültig; der neue Link geht zusätzlich per Mail an den Nutzer. per_email_gesendet ist nur dann true, wenn die Mail tatsächlich versandt wurde. Bei einer vorübergehenden Störung auf unserer Seite antwortet der Endpoint 500 interner_fehler — nicht 404; dann später erneut versuchen.
Idempotenz
Der Idempotenz-Schlüssel ist Ihr Partner-Name zusammen mit der referenz_id — ohne Zeitfenster. Ein zweiter Push mit derselben referenz_id antwortet, egal wann, 200 mit "idempotent": true und dem bestehenden Fall. Stammdaten, Fall und Angebot bleiben dabei unverändert — auch mandant_eigenschaft und callback_url —, und es entsteht kein neuer Zugangslink; dafür gibt es den Endpoint oben.
Einzige Ausnahme: Ein Strukturdaten-Block, der beim ersten Push fehlte oder unvollständig blieb, wird ergänzt — nur bei derselben schema_version, ein unvollständiger Block nur mit derselben Zeilenzahl. warnungen sagt dann, was ergänzt wurde.
Trifft die referenz_id einen Fall, der zu einer anderen Kanzlei gehört als Ihr Schlüssel, antwortet die Schnittstelle 403 kanzlei_mismatch — ohne Falldaten und ohne Änderung am Fall.
Ohne referenz_id gibt es keinen Schutz: jeder Retry legt einen neuen Fall an. Empfehlung: referenz_id = <Ihre Nutzer-ID>-<Steuerjahr> oder eine UUID pro Klick.
Status-Callbacks
Wenn Sie eine callback_url angeben und sie bei der Annahme nicht verworfen wurde, legt Passion Tax Rückmeldungen in eine Zustell-Warteschlange und sendet sie als POST-Request an Ihre URL. Zugesagt ist nur case.assigned direkt nach dem Push; die übrigen Events hängen an Schritten der Kanzlei oder des Mandanten (siehe unten).
POST {your-callback-url}
Content-Type: application/json
User-Agent: PassionTax-Webhook/1.0
X-PassionTax-Event: case.assigned
X-PassionTax-Delivery: 7c1c5f3e-… (UUID, zur Deduplizierung)
X-PassionTax-Signature: sha256=<hex> (HMAC-SHA256 über den Raw-Body)
{
"event": "case.assigned",
"fall_id": "cd20024c-…",
"fall_nummer": "TT-2026-0142",
"referenz_id": "app-user-8821-2026",
"new_status": "zugewiesen",
"steuerberater": { "name": "Maria Muster" },
"kanzlei": { "id": "…", "name": "Muster Steuerberatung" },
"produkt_code": "SP-E03",
"timestamp": "2026-09-05T12:00:00.000Z"
}Der Callback enthält keinen Zugangslink — der ist ein Login-Token und steht nur im synchronen 201-Response. Verloren? Dann über den Zugangslink-Endpoint erneuern.
Events, die heute tatsächlich gesendet werden
case.assigneddirekt nach dem Intake, wenn ein Berater zugewiesen wurde — bei Kanzlei-Bindung immer. Das einzige zugesagte Event.case.createddirekt nach dem Intake ohne Zuweisung (nur bei Schlüsseln ohne Kanzlei-Bindung)case.completeddie Kanzlei schließt den Fall ab (Status geliefert)case.ratedder Mandant bewertet den abgeschlossenen Fall (Status bewertet)case.status_changedeine sonstige Statusänderung über die Fall-Schnittstelle von Passion Tax (bei einer Neuzuweisung: case.assigned)
Die Events nach dem Intake tragen nur event, fall_id, fall_nummer, referenz_id, new_status und timestamp. Keine Rückmeldung gibt es für die Annahme oder Ablehnung des Kostenvoranschlags, die Bestätigung des Personenprofils, den Beginn der Bearbeitung, den Fortschritt und für Zahlungen (zur Online-Zahlung siehe Nach dem Push). Quittieren Sie auch ein Event, das Sie nicht auswerten, mit 2xx.
Zustellung
Timeout 8 Sekunden, Antwort 2xx gilt als zugestellt. Sonst wiederholen wir nach 1 min, 5 min, 15 min, 1 h und 6 h; danach wird die Zustellung als „dead letter“ markiert und ist im Passion-Tax-Admin sichtbar. Ihr Endpoint muss idempotent auf X-PassionTax-Delivery sein, weil dieselbe Zustellung mehrfach eintreffen kann; eine von Hand erneut gesendete, bereits zugestellte Rückmeldung kommt mit einer neuen Delivery-ID.
Keine Weiterleitungen: Jeder Versuch geht an genau die geprüfte callback_url. Eine Antwort 3xx wird nicht verfolgt, sondern gilt als fehlgeschlagener Versuch („Weiterleitung nicht erlaubt“) und läuft durch die Wiederholungen bis ins Dead Letter. Eine URL, die umleitet, wird also nie beliefert — tragen Sie die endgültige URL ein. Zeigt der Host auf eine interne Adresse oder ist die URL strukturell unzulässig, geht die Zustellung ohne Wiederholung sofort ins Dead Letter.
Signatur prüfen
import crypto from "node:crypto";
function verify(rawBody, signatureHeader, secret) {
const expected =
"sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
return signatureHeader?.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected));
}Hashen Sie den unveränderten Raw-Body, nicht das geparste und neu serialisierte JSON. Passion Tax stellt nie ohne Signatur zu: Ist zu Ihrem Schlüssel kein Callback-Secret auflösbar, unterbleibt die Zustellung und läuft durch die Wiederholungen bis ins Dead Letter. Fehlt die Kopfzeile, stammt der Request nicht von uns.
Fehler und Wiederholung
Antworten der Anwendung sind JSON mit error und code; details steht nur bei 400 validierung. Antworten des vorgeschalteten Proxys haben keinen JSON-Körper (siehe unten).
{
"error": "lesbare Meldung",
"code": "maschinenlesbar",
"details": {
"formErrors": [],
"fieldErrors": { "mandant.email": ["Invalid email address"] }
}
}Werten Sie code aus, nicht den Meldungstext — der Text kann sich ändern. In details.fieldErrors steht der volle Feldpfad, bei Array-Elementen mit Index.
| HTTP | code | Bedeutung |
|---|---|---|
| 400 | json_ungueltig | Body ist kein JSON |
| 400 | validierung | Schema verletzt — das verletzte Feld steht als voller Pfad in details.fieldErrors, z. B. mandant.email oder strukturdaten.transaktionen.41207.wert_eur. |
| 401 | auth_fehlt · key_ungueltig | Header fehlt, Schlüssel unbekannt oder deaktiviert |
| 403 | keine_berechtigung | Schlüssel ohne intake-Recht |
| 403 | kanzlei_mismatch | kanzlei_slug passt nicht zur Kanzlei des Schlüssels — oder die referenz_id trifft einen Fall einer anderen Kanzlei (dann ohne Falldaten) |
| 404 | fall_nicht_gefunden | nur beim Zugangslink-Endpoint: kein mit diesem Schlüssel angelegter Fall |
| 409 | konto_konflikt | Die E-Mail gehört zu einem Berater- oder Admin-Konto. Nicht wiederholen, andere E-Mail erfragen. |
| 413 | dokument_zu_gross | Base64-Dokument > 15 MB oder Base64-Dokumente zusammen > 40 MB. Einen Request-Body > 45 MB weist schon der Proxy mit 413 als HTML ab (siehe unten). |
| 422 | produkt_unbekannt | produkt_code unbekannt oder inaktiv |
| 429 | rate_limit | siehe Retry-After; mit derselben referenz_id wiederholen |
| 503 | kanzlei_ohne_berater | Die Ziel-Kanzlei hat kein zuweisbares Mitglied — nicht wiederholen, Support kontaktieren |
| 500 | konto_fehlgeschlagen · profil_fehlgeschlagen · fall_fehlgeschlagen · interner_fehler | mit derselben referenz_id wiederholen (Backoff) |
Antworten des vorgeschalteten Proxys
Diese Antworten kommen als HTML-Seite ohne JSON-Körper und damit ohne code. Werten Sie zuerst den HTTP-Status aus und lesen Sie den Körper nur dann als JSON, wenn er sich als JSON lesen lässt.
| HTTP | Ursache |
|---|---|
| 413 | Request-Body größer als 45 MB — der Request erreicht die Anwendung nicht |
| 502 | Anwendung nicht erreichbar, etwa während eines Neustarts |
| 504 | Anwendung hat nicht binnen 120 Sekunden geantwortet. Der Push kann trotzdem vollständig verarbeitet worden sein. |
Wiederholungsregel
Wiederholen Sie nur bei 429 (nach Retry-After Sekunden), bei 500 und bei Antworten ohne JSON-Körper (502, 504) — außer 413 — und immer mit derselben referenz_id. Nach einem Timeout, Ihrem eigenen oder einem 504, frühestens nach 5 Minuten: der erste Versuch kann serverseitig noch laufen; die Wiederholung findet den Fall danach über die Idempotenz, statt einen zweiten anzulegen. Client-Timeout mindestens 130 Sekunden, damit Sie das 504 des Proxys erhalten, statt vorher selbst abzubrechen.
409, 422 und 503 nicht wiederholen. Alle übrigen 4xx — auch 413 — scheitern unverändert erneut: erst Payload, Schlüssel oder Einstellung korrigieren. Ohne referenz_id nicht automatisch wiederholen, sonst entsteht jedes Mal ein neuer Fall.
Nach dem Push
- Passion Tax legt den Mandanten an oder erkennt ihn an der E-Mail wieder, speichert Stammdaten, Dokumente, Strukturdaten und gegebenenfalls den KYC-Nachweis und weist den Fall der Kanzlei Ihres Schlüssels zu. Der Berater bekommt eine Mail.
- Der Mandant öffnet den Fall über den Zugangslink — Ihren Button oder die Zugangs-Mail.
- Bei
angebot.automatischund Festpreis-Produkt steht dort der Kostenvoranschlag offen. Bevor der Mandant ihn annehmen kann, bestätigt er einmalig sein vorausgefülltes Personenprofil: die von Ihnen gelieferten Stammdaten stehen dort bereits, der Kostenvoranschlag verlinkt die Seite, bestätigt wird mit „Meine Angaben sind weiterhin richtig“. Ohne diese Bestätigung nimmt Passion Tax die Annahme nicht entgegen. - Danach nimmt der Mandant den Kostenvoranschlag an und bestätigt damit den Steuerberatungsvertrag — als Verbraucher (
mandant_eigenschaft: verbraucher) zusätzlich mit Zustimmung zur Widerrufsbelehrung. Ob und wann er das tut, erfahren Sie über die Schnittstelle nicht. - Online-Zahlung, sobald die Kanzlei verifiziert und auf Live geschaltet ist: Die Online-Zahlung über Passion Tax wird für eine Kanzlei freigeschaltet, sobald sie sich bei unserem Zahlungsanbieter Mollie verifiziert hat und ihre Anbindung auf Live geschaltet ist. Bis dahin ist sie für diese Kanzlei noch nicht möglich: Der Mandant liest nach der Annahme, dass die Online-Zahlung freigeschaltet wird, sobald seine Kanzlei die Einrichtung abgeschlossen hat, und dass er jetzt nichts bezahlen muss.
Planen Sie Ihre Nutzerführung entsprechend: Der Klick in Ihrer App übergibt den Vorgang und öffnet ihn beim Steuerberater — er schließt nichts ab. Versprechen Sie weder „annehmen und zahlen“ noch einen Abschluss mit einem Klick. Solange die Kanzlei Ihres Schlüssels nicht bei Mollie verifiziert und auf Live geschaltet ist, darf Ihre App keine sofortige Zahlung versprechen. Ob sie es ist, meldet die Schnittstelle nicht — fragen Sie bei api@passion.tax nach, bevor Ihre App eine Zahlung ankündigt. Steht die Bestätigung des Personenprofils beim Push noch aus, weist die 201-Antwort in warnungen darauf hin.
Datenschutz
Übermitteln Sie nur Daten, deren Weitergabe der Nutzer zugestimmt hat (einwilligung). Passion Tax protokolliert angenommene und inhaltlich abgelehnte Calls mit Schlüssel, Referenz, Ergebnis, Payload-Hash, Umfang und Einwilligungs-Attest, bei angelegten Fällen auch Empfänger und Ergebnis der Zugangs-Mail — nicht den Klartext-Payload.
Die Schnittstelle ist kein Auskunftsweg über Dritte. Der Trockenlauf sagt nicht, ob zu einer E-Mail-Adresse ein Mandantenkonto besteht; er meldet nur ein Berater- oder Admin-Konto (konto_konflikt), an dem der echte Push ohnehin scheitert. Der echte Push dagegen zeigt ein bestehendes Mandantenkonto (siehe Antwort und Zugangslink). Eine referenz_id gibt nie Daten eines Falls einer anderen Kanzlei preis. Callbacks enthalten außer dem Namen des zugewiesenen Beraters keine Personendaten und keinen Zugangslink.
Test und Onboarding
- Sie erhalten Schlüssel und Callback-Secret. Der Schlüssel ist an die Kanzlei gebunden, die Ihre Nutzer betreut.
- Entwicklung gegen
?dry_run=1: es entsteht kein Konto, kein Fall und keine Mail. Die Beispiele dieser Seite wörtlich nur so absenden. - Echte Test-Pushes nur nach Absprache mit Passion Tax: mit einem eigenen Testschlüssel an einer Testkanzlei, ohne kyc-Block und mit E-Mail-Adressen, die Ihnen gehören.
- Produktiv: Limit passend setzen lassen, Warteschlange mit Wiederholung nach der Regel oben, Callback-Signatur prüfen.
Es gibt keinen Löschweg für Partner-Fälle — weder über die Schnittstelle noch für die Kanzlei. Identitätsnachweise und Zustimmungsbelege sind append-only. Ein Test-Push mit kyc-Block hinterlässt deshalb dauerhaft einen Identitätsnachweis; einer an eine fremde Adresse schickt dieser Person einen Anmeldelink.
Beispiel
Entwickeln Sie gegen ?dry_run=1 — so entsteht kein Konto, kein Fall und keine Mail. Senden Sie dieses Beispiel wörtlich nur als Trockenlauf: ein echter Push legt einen echten Mandanten und Fall an, die sich nicht löschen lassen. Die Beispieladresse liegt unter der reservierten Top-Level-Domain .example und erhält nie eine Mail.
curl -X POST "https://passion.tax/api/webhooks/intake?dry_run=1" \
-H "Authorization: Bearer ptk_a1b2c3d4e5f6..." \
-H "Content-Type: application/json" \
-d '{
"produkt_code": "SP-E03",
"referenz_id": "app-user-8821-2026",
"mandant_eigenschaft": "verbraucher",
"callback_url": "https://api.mining-app.example/passiontax/callback",
"mandant": {
"externe_id": "user-8821",
"vorname": "Max",
"nachname": "Mustermann",
"email": "max.mustermann@beispiel.example",
"typ": "privatperson"
},
"einwilligung": {
"erteilt_am": "2026-09-01T10:05:00Z",
"text_version": "consent-de-v3",
"datenweitergabe_an_kanzlei": true,
"plattform_agb_akzeptiert": true,
"quelle": "screen:tax-handover"
},
"angebot": { "automatisch": true }
}'Kontakt
Bei Fragen zur API oder für die Beantragung eines Schlüssels: api@passion.tax
