{
  "openapi": "3.1.0",
  "info": {
    "title": "Ryh API v1",
    "version": "2026-07-01",
    "summary": "Anbieter, Connectoren, Fähigkeiten und Verbindungen im Ryh-Netz.",
    "description": "Die Ryh API wird ausschließlich serverseitig aufgerufen. Zugangsschlüssel bleiben im Backend des Partners. Schreibende Aufrufe brauchen einen Vorgangsschlüssel, damit ein Wiederholungsversuch nie doppelt wirkt.",
    "contact": {
      "name": "Ryh Partner Support",
      "url": "https://developer.ryh.de"
    }
  },
  "servers": [
    {
      "url": "https://api.ryh.de",
      "description": "Produktion"
    },
    {
      "url": "https://ryh.de",
      "description": "Gleiche Schnittstelle über die Hauptdomain"
    }
  ],
  "tags": [
    {
      "name": "Übersicht",
      "description": "Selbstauskunft der Schnittstelle"
    },
    {
      "name": "Netz",
      "description": "Anbieter, Connectoren und Fähigkeiten"
    },
    {
      "name": "Verbindungen",
      "description": "Verbindungen eines Betriebs"
    },
    {
      "name": "Vorgänge",
      "description": "Vorgangsschlüssel und Wiederholsicherheit"
    },
    {
      "name": "Live",
      "description": "Laufende Statusmeldungen"
    }
  ],
  "paths": {
    "/api/public/v1": {
      "get": {
        "tags": [
          "Übersicht"
        ],
        "summary": "Übersicht und Fähigkeiten dieser Schnittstelle",
        "security": [],
        "responses": {
          "200": {
            "description": "Selbstauskunft mit Version, Authentifizierung und Routenliste.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "service": {
                          "type": "string"
                        },
                        "surface": {
                          "type": "string"
                        },
                        "version": {
                          "type": "string"
                        },
                        "authentication": {
                          "type": "object",
                          "additionalProperties": true
                        },
                        "idempotency": {
                          "type": "object",
                          "additionalProperties": true
                        },
                        "routes": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/RouteInfo"
                          }
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v1/providers": {
      "get": {
        "tags": [
          "Netz"
        ],
        "summary": "Anbieter im Ryh-Netz auflisten",
        "security": [
          {
            "bearerAuth": [],
            "tenantHeader": []
          }
        ],
        "parameters": [
          {
            "name": "category",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Auf eine Kategorie eingrenzen."
          }
        ],
        "responses": {
          "200": {
            "description": "Anbieterliste.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "count": {
                          "type": "integer"
                        },
                        "providers": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Provider"
                          }
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "428": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "500": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/public/v1/connectors": {
      "get": {
        "tags": [
          "Netz"
        ],
        "summary": "Connectoren auflisten, optional gefiltert",
        "security": [
          {
            "bearerAuth": [],
            "tenantHeader": []
          }
        ],
        "parameters": [
          {
            "name": "capability",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "providerId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Connectorliste.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "count": {
                          "type": "integer"
                        },
                        "connectors": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Connector"
                          }
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "428": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "500": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/public/v1/capabilities": {
      "get": {
        "tags": [
          "Netz"
        ],
        "summary": "Katalog aller Fähigkeiten",
        "security": [
          {
            "bearerAuth": [],
            "tenantHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "Fähigkeitskatalog.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "count": {
                          "type": "integer"
                        },
                        "capabilities": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Capability"
                          }
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "428": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "500": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "tags": [
          "Netz"
        ],
        "summary": "Fähigkeit eines Connectors prüfen",
        "security": [
          {
            "bearerAuth": [],
            "tenantHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "connectorId",
                  "capability"
                ],
                "properties": {
                  "connectorId": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120
                  },
                  "capability": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120
                  },
                  "environment": {
                    "type": "string",
                    "enum": [
                      "development",
                      "sandbox",
                      "pilot",
                      "production"
                    ],
                    "default": "sandbox"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Entscheidung inklusive Begründung.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "decision": {
                          "$ref": "#/components/schemas/CapabilityDecision"
                        },
                        "environment": {
                          "type": "string",
                          "enum": [
                            "development",
                            "sandbox",
                            "pilot",
                            "production"
                          ]
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "428": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "500": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/public/v1/connections": {
      "get": {
        "tags": [
          "Verbindungen"
        ],
        "summary": "Verbindungen des eigenen Betriebs",
        "security": [
          {
            "bearerAuth": [],
            "tenantHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "Verbindungsliste des Betriebs.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "tenant": {
                          "type": "string"
                        },
                        "count": {
                          "type": "integer"
                        },
                        "connections": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Connection"
                          }
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "428": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "500": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "tags": [
          "Verbindungen"
        ],
        "summary": "Verbindung anlegen (idempotent)",
        "security": [
          {
            "bearerAuth": [],
            "tenantHeader": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._:-]{8,128}$"
            },
            "description": "Vorgangsschlüssel. Gleicher Schlüssel und gleicher Inhalt liefern dieselbe Antwort erneut."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "connectorId",
                  "environment",
                  "scopeLabel",
                  "capabilities"
                ],
                "properties": {
                  "connectorId": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120
                  },
                  "environment": {
                    "type": "string",
                    "enum": [
                      "development",
                      "sandbox",
                      "pilot",
                      "production"
                    ]
                  },
                  "scopeLabel": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120,
                    "description": "Sprechender Name, z. B. der Name des Lokals."
                  },
                  "capabilities": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 24,
                    "items": {
                      "type": "string",
                      "minLength": 2,
                      "maxLength": 120
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verbindung angelegt oder Wiederholung derselben Antwort.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/Connection"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "428": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "500": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/public/v1/idempotency-keys": {
      "post": {
        "tags": [
          "Vorgänge"
        ],
        "summary": "Neuen Vorgangsschlüssel erzeugen",
        "security": [
          {
            "bearerAuth": [],
            "tenantHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "operation"
                ],
                "properties": {
                  "operation": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 80,
                    "description": "Kurzname des Vorgangs, z. B. connection.create."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Neuer Schlüssel mit Gültigkeitsdauer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "idempotencyKey": {
                          "type": "string"
                        },
                        "operation": {
                          "type": "string"
                        },
                        "expiresAt": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "428": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "500": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/public/v1/stream": {
      "get": {
        "tags": [
          "Live"
        ],
        "summary": "Laufende Statusmeldungen (Server-Sent Events)",
        "description": "Liefert Zustandsänderungen fortlaufend. Nach einem Abbruch wird mit 'Last-Event-ID' oder '?cursor=' lückenlos weitergelesen; jede Meldung trägt eine fortlaufende Nummer und kommt genau einmal an.",
        "security": [],
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Zuletzt gelesene Nummer."
          },
          {
            "name": "Last-Event-ID",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ereignisstrom.",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v1/openapi.json": {
      "get": {
        "tags": [
          "Übersicht"
        ],
        "summary": "Diese Beschreibung als OpenAPI-Dokument",
        "security": [],
        "responses": {
          "200": {
            "description": "OpenAPI 3.1 Dokument.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Zugangsschlüssel des Partners. Nur serverseitig senden, nie im Browser."
      },
      "tenantHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "x-ryh-tenant",
        "description": "Kennung des Betriebs."
      }
    },
    "responses": {
      "Error": {
        "description": "Fehlermeldung mit klarer Ursache und nächstem Schritt.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Failure"
            }
          }
        }
      }
    },
    "schemas": {
      "Meta": {
        "type": "object",
        "required": [
          "requestId",
          "version",
          "at"
        ],
        "properties": {
          "requestId": {
            "type": "string",
            "description": "Kennung dieses Aufrufs für Rückfragen."
          },
          "version": {
            "type": "string",
            "example": "2026-07-01"
          },
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "idempotencyKey": {
            "type": "string"
          },
          "replayed": {
            "type": "boolean",
            "description": "Antwort stammt aus einem früheren, gleichen Vorgang."
          }
        }
      },
      "Failure": {
        "type": "object",
        "required": [
          "ok",
          "error",
          "meta"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "unauthorized",
                  "forbidden",
                  "not_found",
                  "invalid_request",
                  "capability_denied",
                  "idempotency_conflict",
                  "idempotency_required",
                  "rate_limited",
                  "internal"
                ]
              },
              "message": {
                "type": "string"
              },
              "detail": {
                "type": "string"
              },
              "hint": {
                "type": "string"
              }
            }
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "RouteInfo": {
        "type": "object",
        "properties": {
          "method": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "purpose": {
            "type": "string"
          },
          "auth": {
            "type": "boolean"
          }
        }
      },
      "Provider": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "Connector": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "providerId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": true
      },
      "Capability": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "critical": {
            "type": "boolean"
          },
          "idempotencyRequired": {
            "type": "boolean"
          }
        },
        "additionalProperties": true
      },
      "CapabilityDecision": {
        "type": "object",
        "required": [
          "connectorId",
          "capability",
          "allowed",
          "critical",
          "idempotencyRequired",
          "reason"
        ],
        "properties": {
          "connectorId": {
            "type": "string"
          },
          "capability": {
            "type": "string"
          },
          "allowed": {
            "type": "boolean"
          },
          "critical": {
            "type": "boolean"
          },
          "idempotencyRequired": {
            "type": "boolean"
          },
          "reason": {
            "type": "string"
          }
        }
      },
      "Connection": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "connectorId": {
            "type": "string"
          },
          "environment": {
            "type": "string",
            "enum": [
              "development",
              "sandbox",
              "pilot",
              "production"
            ]
          },
          "scopeLabel": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "capability": {
                  "type": "string"
                },
                "critical": {
                  "type": "boolean"
                },
                "idempotencyRequired": {
                  "type": "boolean"
                }
              }
            }
          },
          "nextStep": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    }
  }
}