{
  "openapi": "3.1.0",
  "info": {
    "title": "Studienplatztausch Medizin API",
    "version": "1.1.0",
    "description": "Öffentliche API des Portals studienplatztausch-medizin.de. Zwei Fähigkeiten: (1) Tauschchancen zwischen zwei Universitäten abfragen, (2) ein Studienplatztausch-Gesuch einreichen. Unterstützte Studiengänge: Humanmedizin, Zahnmedizin und Tiermedizin — die wählbaren Universitäten hängen vom Studiengang ab (Tiermedizin nur 5 Fakultäten, Zahnmedizin 29). Das Einreichen ist per Double-Opt-in abgesichert: Das Gesuch wird erst am automatischen Abgleich beteiligt, nachdem die angegebene Person den Bestätigungslink in ihrer E-Mail geklickt hat.",
    "contact": { "email": "kontakt@studienplatztausch-medizin.de" },
    "license": { "name": "Nutzung frei für nicht-kommerzielle Zwecke" }
  },
  "servers": [{ "url": "https://www.studienplatztausch-medizin.de" }],
  "paths": {
    "/api/chancen.php": {
      "get": {
        "operationId": "getTauschchancen",
        "summary": "Tauschchancen zwischen zwei Unis abfragen",
        "description": "Ohne Parameter: liefert die gültigen Universitäten und Studienphasen. Mit von + nach: liefert eine Chancen-Bewertung (1–3 Sterne) als Nachfrage-/Angebotsindikator. Datenbasis ist ein historischer Snapshot (Stand 09.07.2026) des im Juli 2026 eingestellten bundesweiten Tauschportals — kein Live-Abbild der aktuellen Gesuche und keine gemessene Erfolgswahrscheinlichkeit. Keine Authentifizierung nötig, nur öffentliche Aggregatdaten. Antwort ist cachebar (max-age 3600).",
        "parameters": [
          { "name": "von", "in": "query", "required": false, "description": "Aktuelle Universität (Ist-Uni). Exakter Name aus der Uni-Liste.", "schema": { "type": "string", "example": "Uni Bonn" } },
          { "name": "nach", "in": "query", "required": false, "description": "Wunsch-Universität. Exakter Name aus der Uni-Liste.", "schema": { "type": "string", "example": "LMU München" } },
          { "name": "phase", "in": "query", "required": false, "description": "Studienphase zum Tauschzeitpunkt (optional). Gültige Werte siehe Metadaten-Antwort.", "schema": { "type": "string", "example": "1. klinischen" } },
          { "name": "studiengang", "in": "query", "required": false, "description": "Optional, Default Humanmedizin. Bestimmt gültige Uni-/Phasenwerte.", "schema": { "type": "string", "enum": ["Humanmedizin", "Zahnmedizin", "Tiermedizin"], "default": "Humanmedizin" } }
        ],
        "responses": {
          "200": {
            "description": "Chancen-Bewertung oder Metadaten",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean" },
                    "von": { "type": "string" },
                    "nach": { "type": "string" },
                    "phase": { "type": "string" },
                    "sterne": { "type": "integer", "minimum": 1, "maximum": 3, "description": "Nachfrage-/Angebotsindikator, KEINE gemessene Erfolgswahrscheinlichkeit" },
                    "einschaetzung": { "type": "string" },
                    "nachfrage_wunschuni": { "type": "integer", "description": "Wie viele wollen zur Wunsch-Uni" },
                    "angebot_wunschuni": { "type": "integer", "description": "Wie viele wollen von der Wunsch-Uni weg" },
                    "direkte_tauschpartner": { "type": "integer", "description": "Gesuche, die exakt den Gegenweg wollen" }
                  }
                }
              }
            }
          },
          "422": { "description": "Ungültige Uni oder Phase", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Fehler" } } } }
        }
      }
    },
    "/api/gesuch.php": {
      "post": {
        "operationId": "submitTauschgesuch",
        "summary": "Studienplatztausch-Gesuch einreichen",
        "description": "Reicht ein Tauschgesuch ein (Humanmedizin, Zahnmedizin oder Tiermedizin). Das Gesuch wird NICHT sofort am automatischen Abgleich beteiligt: An die angegebene E-Mail geht eine Bestätigungsmail; erst nach Klick auf den Link (Double-Opt-in) wird es aktiv und die Person erhält eine PIN zur Verwaltung. Je E-Mail-Adresse ist pro Tauschzeitpunkt genau EIN Gesuch möglich (max. vier, so viele Zeitpunkte gibt es) — andere Wunsch-Unis werden durch Bearbeiten des bestehenden Gesuchs im Login-Bereich geändert, nicht durch ein zweites Gesuch. Die wählbaren Universitäten hängen vom Studiengang ab. Rate-Limit: 4 Anfragen pro Stunde und IP sowie 4 pro Tag und E-Mail-Adresse.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["vorname", "nachname", "email", "ist_uni", "phase", "zeitpunkt", "wunsch", "datenschutz"],
                "properties": {
                  "vorname": { "type": "string", "maxLength": 80 },
                  "nachname": { "type": "string", "maxLength": 80, "description": "Pflichtfeld." },
                  "email": { "type": "string", "format": "email" },
                  "telefon": { "type": "string", "maxLength": 40, "description": "Optional." },
                  "studiengang": { "type": "string", "enum": ["Humanmedizin", "Zahnmedizin", "Tiermedizin"], "default": "Humanmedizin", "description": "Optional; ohne Angabe Humanmedizin. Bestimmt, welche Universitäten und Phasen gültig sind." },
                  "ist_uni": { "type": "string", "description": "Aktuelle Universität. Gültige Werte hängen vom Studiengang ab (Metadaten via /api/chancen.php)." },
                  "phase": { "type": "string", "description": "Studienphase. Humanmedizin z. B. '1. klinisches Semester'; Tiermedizin '1.–11. Semester'; Zahnmedizin '1.–10. Semester'." },
                  "zeitpunkt": { "type": "string", "description": "Tauschzeitpunkt, z. B. 'Wintersemester 2026/2027'. Vier Werte zur Auswahl." },
                  "wunsch": { "type": "array", "items": { "type": "string" }, "minItems": 1, "description": "Mindestens eine Wunsch-Universität; nach oben nur durch die Standortliste des Studiengangs begrenzt (nicht die eigene Ist-Uni)." },
                  "mail_frequenz": { "type": "string", "enum": ["sofort", "taeglich", "woechentlich"], "default": "sofort", "description": "Optional. Bestimmt, ob Match-Benachrichtigungen sofort einzeln oder als tägliche/wöchentliche Sammel-Mail zugestellt werden." },
                  "mag_direkt": { "type": "boolean", "default": true, "description": "Optional. Nur bei true wird für Direkttausch (2 Personen) gematcht." },
                  "mag_ring3": { "type": "boolean", "default": true, "description": "Optional. Nur bei true wird für 3er-Ringtausch gematcht." },
                  "mag_ring4": { "type": "boolean", "default": true, "description": "Optional. Nur bei true wird für 4er-Ringtausch gematcht. Mindestens eine der drei mag_*-Optionen muss true sein." },
                  "datenschutz": { "type": "boolean", "description": "Muss true sein: Einwilligung in die Datenverarbeitung zur Vermittlung. Das Gesuch erscheint mit Vorname + Initial im öffentlichen Ticker (Details in der Datenschutzerklärung)." }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Gesuch angelegt, Bestätigungsmail eingereiht",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "chiffre": { "type": "string", "description": "Pseudonyme Kennung des Gesuchs" }, "mail": { "type": "string", "enum": ["sent", "pending"], "description": "'sent' = Bestätigungsmail sofort zugestellt, 'pending' = eingereiht und wird per Retry zugestellt. In beiden Fällen ist das Gesuch angelegt." } } } } }
          },
          "409": { "description": "Für diesen Tauschzeitpunkt existiert bereits ein bestätigtes Gesuch dieser E-Mail-Adresse (bestehendes bearbeiten statt neu anlegen)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Fehler" } } } },
          "422": { "description": "Validierungsfehler (fehlende Pflichtfelder, ungültige Uni/Phase/Zeitpunkt für den Studiengang, Datenschutz nicht bestätigt)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Fehler" } } } },
          "429": { "description": "Rate-Limit überschritten (4/Stunde/IP oder 4/Tag/E-Mail)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Fehler" } } } }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Fehler": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean", "example": false },
          "error": { "type": "string", "description": "Menschenlesbare Fehlermeldung" }
        }
      }
    }
  }
}
