{
  "openapi": "3.1.0",
  "info": {
    "title": "Sattelpass Partner-API",
    "version": "1.0.0",
    "description": "Schnittstelle für Händler, Hersteller und Fremdsysteme (CRM, Warenwirtschaft, eigene Apps): Sättel anlegen, suchen und ändern, Chronik-Einträge schreiben, öffentlichen Sattelpass lesen. Ereignisse werden per Webhook (HMAC-SHA256-signiert) zurückgemeldet. Dokumentation: https://sattelpass.com/entwickler",
    "contact": {
      "name": "Sattelpass",
      "email": "kontakt@sattelpass.com",
      "url": "https://sattelpass.com/entwickler"
    }
  },
  "servers": [
    {
      "url": "https://sattelpass.com/api/v1",
      "description": "Produktion (Kurzadresse)"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    },
    {
      "apiKeyHeader": []
    }
  ],
  "tags": [
    {
      "name": "Konto"
    },
    {
      "name": "Sättel"
    },
    {
      "name": "Chronik"
    },
    {
      "name": "Öffentlich"
    },
    {
      "name": "Webhooks"
    },
    {
      "name": "Kunden",
      "description": "Eigener Kundenstamm (Kunden, denen Sättel zugeordnet werden)"
    }
  ],
  "paths": {
    "/me": {
      "get": {
        "tags": ["Konto"],
        "summary": "Konto und Schlüsselrechte",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "api_version": {
                      "type": "string",
                      "example": "v1"
                    },
                    "account": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "display_name": {
                          "type": "string"
                        },
                        "roles": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "verified": {
                          "type": "boolean"
                        }
                      }
                    },
                    "key": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "kind": {
                          "type": "string",
                          "enum": ["secret", "embed"]
                        },
                        "scopes": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "rate_limit_per_minute": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/options": {
      "get": {
        "tags": ["Konto"],
        "summary": "Auswahlwerte (Hersteller-Konfiguration) und Feldliste",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "brand": {
                      "type": "string"
                    },
                    "fields": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "required": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "options": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "value": {
                              "type": "string"
                            },
                            "is_default": {
                              "type": "boolean"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/saddles": {
      "post": {
        "tags": ["Sättel"],
        "summary": "Sattel anlegen",
        "description": "Legt einen Sattel im Konto des Schlüsselinhabers an, erzeugt den Kurzcode (NFC/QR) und den ersten Chronik-Eintrag. Mit `Idempotency-Key` sind Wiederholungen ungefährlich; `external_id` verhindert Doppelanlagen je Konto.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaddleCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Angelegt",
            "headers": {
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string"
                },
                "description": "`true`, wenn die Antwort aus einer früheren Anfrage mit demselben Idempotency-Key stammt."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "saddle": {
                      "$ref": "#/components/schemas/Saddle"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "get": {
        "tags": ["Sättel"],
        "summary": "Eigene Sättel suchen",
        "parameters": [
          {
            "name": "serial",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Seriennummer (exakt, Groß-/Kleinschreibung egal)"
          },
          {
            "name": "external_id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "short_code",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Volltext in Marke, Modell, Seriennummer, Kurzcode"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "saddles": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Saddle"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/saddles/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/SaddleId"
        }
      ],
      "get": {
        "tags": ["Sättel"],
        "summary": "Sattel lesen",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "saddle": {
                      "$ref": "#/components/schemas/Saddle"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "patch": {
        "tags": ["Sättel"],
        "summary": "Stammdaten ändern",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaddleUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "saddle": {
                      "$ref": "#/components/schemas/Saddle"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "Mit `customer_id` oder `customer { email, first_name, last_name, phone }` lässt sich der Sattel einem (anderen) Kunden Ihres Kundenstamms zuordnen; `customer: null` entfernt die Zuordnung."
      }
    },
    "/saddles/{id}/events": {
      "parameters": [
        {
          "$ref": "#/components/parameters/SaddleId"
        }
      ],
      "get": {
        "tags": ["Chronik"],
        "summary": "Chronik lesen",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "events": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SaddleEvent"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": ["Chronik"],
        "summary": "Chronik-Eintrag anlegen",
        "description": "Nur für verifizierte Konten (Fehler NOT_VERIFIED). `public_note` erscheint auf dem öffentlichen Sattelpass.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaddleEventCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Angelegt",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "event": {
                      "$ref": "#/components/schemas/SaddleEvent"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/public/saddles/{short_code}": {
      "get": {
        "tags": ["Öffentlich"],
        "summary": "Öffentlicher Sattelpass (wie beim Scan)",
        "parameters": [
          {
            "name": "short_code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "saddle": {
                      "type": "object"
                    },
                    "events": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/webhooks": {
      "get": {
        "tags": ["Webhooks"],
        "summary": "Eigene Webhook-Endpunkte und letzte Zustellungen",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "endpoints": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookEndpoint"
                      }
                    },
                    "deliveries": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookDelivery"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/saddles/{id}/events/{event_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/SaddleId"
        },
        {
          "name": "event_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "patch": {
        "tags": ["Chronik"],
        "summary": "Chronik-Eintrag ändern (nur eigene Einträge)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaddleEventCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "event": {
                      "$ref": "#/components/schemas/SaddleEvent"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "tags": ["Chronik"],
        "summary": "Chronik-Eintrag entfernen (wird archiviert, nur eigene Einträge)",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/customers": {
      "get": {
        "tags": ["Kunden"],
        "summary": "Eigenen Kundenstamm lesen",
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "external_id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 200
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "customers": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Customer"
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": ["Kunden"],
        "summary": "Kunde anlegen oder aktualisieren",
        "description": "Abgleich zuerst über `external_id`, sonst über die E-Mail. Vorhandene Kunden werden aktualisiert (Antwort 200, `created: false`), neue angelegt (201).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "customer": {
                      "$ref": "#/components/schemas/Customer"
                    },
                    "created": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Angelegt",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "customer": {
                      "$ref": "#/components/schemas/Customer"
                    },
                    "created": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/customers/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": ["Kunden"],
        "summary": "Kunde lesen",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "customer": {
                      "$ref": "#/components/schemas/Customer"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "patch": {
        "tags": ["Kunden"],
        "summary": "Kunde ändern",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "customer": {
                      "$ref": "#/components/schemas/Customer"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/saddles/claim": {
      "post": {
        "tags": ["Sättel"],
        "summary": "Sattel per Kurzcode übernehmen",
        "description": "Übernimmt einen Sattel, der im Konto eines Herstellers liegt (Chip bereits beschrieben), in das eigene Konto und ordnet ihn optional einem Kunden zu. Erlaubt, wenn der bisherige Inhaber ein Hersteller-Konto ist oder der Sattel noch keinem Kunden gehört.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["short_code"],
                "properties": {
                  "short_code": {
                    "type": "string"
                  },
                  "customer_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "customer": {
                    "type": "object",
                    "properties": {
                      "email": {
                        "type": "string"
                      },
                      "first_name": {
                        "type": "string"
                      },
                      "last_name": {
                        "type": "string"
                      },
                      "phone": {
                        "type": "string"
                      }
                    }
                  },
                  "external_id": {
                    "type": "string"
                  },
                  "note": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "saddle": {
                      "$ref": "#/components/schemas/Saddle"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "webhooks": {
    "saddle.created": {
      "post": {
        "summary": "Neuer Sattel (API, Dashboard, App, Import, Einbett-Formular)",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookDeliveryBody"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Empfangen"
          }
        }
      }
    },
    "saddle.updated": {
      "post": {
        "summary": "Stammdaten geändert",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookDeliveryBody"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Empfangen"
          }
        }
      }
    },
    "saddle.owner_changed": {
      "post": {
        "summary": "Kunde/Besitzer geändert",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookDeliveryBody"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Empfangen"
          }
        }
      }
    },
    "transfer.accepted": {
      "post": {
        "summary": "Übergabe angenommen",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookDeliveryBody"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Empfangen"
          }
        }
      }
    },
    "saddle.stolen_reported": {
      "post": {
        "summary": "Diebstahl gemeldet",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookDeliveryBody"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Empfangen"
          }
        }
      }
    },
    "event.created": {
      "post": {
        "summary": "Neuer Chronik-Eintrag",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookDeliveryBody"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Empfangen"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "`Authorization: Bearer sp_live_…` (Server) oder `sp_embed_…` (Browser, an Domain gebunden)"
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Api-Key"
      }
    },
    "parameters": {
      "SaddleId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "maxLength": 200
        },
        "description": "Beliebiger eindeutiger Wert je Anlage (z. B. Belegnummer). Wiederholungen liefern dieselbe Antwort."
      }
    },
    "responses": {
      "Error": {
        "description": "Fehler",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "string",
                      "enum": [
                        "MISSING_KEY",
                        "INVALID_KEY",
                        "INSUFFICIENT_SCOPE",
                        "ORIGIN_NOT_ALLOWED",
                        "NOT_VERIFIED",
                        "NOT_FOUND",
                        "METHOD_NOT_ALLOWED",
                        "DUPLICATE_EXTERNAL_ID",
                        "VALIDATION",
                        "IDEMPOTENCY_MISMATCH",
                        "INVALID_JSON",
                        "RATE_LIMITED",
                        "INTERNAL",
                        "BAD_REQUEST"
                      ]
                    },
                    "message": {
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "schemas": {
      "SaddleFields": {
        "type": "object",
        "properties": {
          "brand": {
            "type": "string",
            "description": "Marke"
          },
          "model": {
            "type": "string",
            "description": "Modell"
          },
          "art": {
            "type": "string",
            "description": "Art / Disziplin"
          },
          "seat_size": {
            "type": "string",
            "description": "Sitzgröße"
          },
          "kammerweite": {
            "type": "string"
          },
          "seriennummer": {
            "type": "string"
          },
          "sattel_typ": {
            "type": "string"
          },
          "sattelbaum": {
            "type": "string"
          },
          "kopfeisen": {
            "type": "string"
          },
          "verstellbar": {
            "type": "string"
          },
          "aktuelle_einstellung": {
            "type": "string"
          },
          "sattelblatt": {
            "type": "string"
          },
          "vorschnitt": {
            "type": "string"
          },
          "pausche": {
            "type": "string"
          },
          "sitz": {
            "type": "string"
          },
          "strupfen": {
            "type": "string"
          },
          "polsterung": {
            "type": "string"
          },
          "leder": {
            "type": "string"
          },
          "farbe": {
            "type": "string"
          },
          "seller_name": {
            "type": "string",
            "description": "Verkäufer / Vertriebspartner"
          }
        }
      },
      "SaddleCreate": {
        "allOf": [
          {
            "$ref": "#/components/schemas/SaddleFields"
          },
          {
            "type": "object",
            "required": ["brand", "model"],
            "properties": {
              "external_id": {
                "type": "string",
                "maxLength": 120,
                "description": "Ihre eigene ID, eindeutig je Konto"
              },
              "photo_url": {
                "type": "string"
              },
              "chip_url": {
                "type": "string",
                "maxLength": 300,
                "description": "Adresse auf Ihrem eigenen NFC-Chip (z. B. https://ihr-betrieb.de/o/CODE); der Sattelpass-Scanner findet den Sattel darüber"
              },
              "created_note": {
                "type": "string",
                "maxLength": 2000,
                "description": "Öffentlicher Text des ersten Chronik-Eintrags"
              },
              "created_title": {
                "type": "string",
                "maxLength": 200
              },
              "customer_id": {
                "type": "string",
                "format": "uuid"
              },
              "customer": {
                "type": "object",
                "required": ["email"],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "first_name": {
                    "type": "string"
                  },
                  "last_name": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "string"
                  }
                }
              }
            }
          }
        ]
      },
      "SaddleUpdate": {
        "allOf": [
          {
            "$ref": "#/components/schemas/SaddleFields"
          },
          {
            "type": "object",
            "properties": {
              "external_id": {
                "type": ["string", "null"]
              },
              "photo_url": {
                "type": ["string", "null"]
              },
              "chip_url": {
                "type": ["string", "null"],
                "maxLength": 300
              },
              "is_active": {
                "type": "boolean"
              },
              "last_check_date": {
                "type": ["string", "null"],
                "format": "date"
              }
            }
          }
        ]
      },
      "Saddle": {
        "allOf": [
          {
            "$ref": "#/components/schemas/SaddleFields"
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "short_code": {
                "type": ["string", "null"],
                "example": "K7PQ2XM9"
              },
              "pass_url": {
                "type": ["string", "null"],
                "example": "https://sattelpass.com/s/K7PQ2XM9"
              },
              "external_id": {
                "type": ["string", "null"]
              },
              "created_via": {
                "type": ["string", "null"],
                "enum": ["app", "web", "import", "api", "embed", null]
              },
              "is_active": {
                "type": "boolean"
              },
              "nfc_written_at": {
                "type": ["string", "null"],
                "format": "date-time"
              },
              "last_check_date": {
                "type": ["string", "null"],
                "format": "date"
              },
              "stolen_reported_at": {
                "type": ["string", "null"],
                "format": "date-time"
              },
              "customer": {
                "type": ["object", "null"],
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "email": {
                    "type": "string"
                  },
                  "first_name": {
                    "type": "string"
                  },
                  "last_name": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "string"
                  }
                }
              },
              "created_at": {
                "type": "string",
                "format": "date-time"
              },
              "updated_at": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        ]
      },
      "SaddleEventCreate": {
        "type": "object",
        "required": ["title"],
        "properties": {
          "event_type": {
            "type": "string",
            "enum": ["work_order", "check", "fitting", "repair", "note", "sale"],
            "default": "work_order"
          },
          "title": {
            "type": "string",
            "maxLength": 200
          },
          "description": {
            "type": "string",
            "maxLength": 4000,
            "description": "Intern (nur für berechtigte Nutzer)"
          },
          "public_note": {
            "type": "string",
            "maxLength": 2000,
            "description": "Auf dem öffentlichen Sattelpass sichtbar"
          },
          "event_date": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SaddleEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "saddle_id": {
            "type": "string",
            "format": "uuid"
          },
          "event_type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "public_note": {
            "type": "string"
          },
          "event_date": {
            "type": "string",
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WebhookEndpoint": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "active": {
            "type": "boolean"
          },
          "last_delivery_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "last_status": {
            "type": ["integer", "null"]
          },
          "disabled_reason": {
            "type": ["string", "null"]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "endpoint_id": {
            "type": "string",
            "format": "uuid"
          },
          "event": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": ["pending", "sending", "delivered", "failed", "dead"]
          },
          "attempts": {
            "type": "integer"
          },
          "response_status": {
            "type": ["integer", "null"]
          },
          "last_error": {
            "type": ["string", "null"]
          },
          "next_attempt_at": {
            "type": "string",
            "format": "date-time"
          },
          "delivered_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WebhookDeliveryBody": {
        "type": "object",
        "description": "Header: X-Sattelpass-Event, X-Sattelpass-Delivery, X-Sattelpass-Timestamp (Unix-Sekunden), X-Sattelpass-Signature = `v1=` + hex(HMAC-SHA256(secret, timestamp + \".\" + rawBody)).",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "event": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "attempt": {
            "type": "integer"
          },
          "api_version": {
            "type": "string",
            "example": "v1"
          },
          "data": {
            "type": "object",
            "properties": {
              "saddle": {
                "$ref": "#/components/schemas/Saddle"
              },
              "event": {
                "$ref": "#/components/schemas/SaddleEvent"
              },
              "transfer": {
                "type": "object"
              },
              "previous_customer_id": {
                "type": ["string", "null"]
              }
            }
          }
        }
      },
      "Customer": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string"
          },
          "first_name": {
            "type": "string"
          },
          "last_name": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "external_id": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CustomerInput": {
        "type": "object",
        "required": ["email"],
        "properties": {
          "email": {
            "type": "string"
          },
          "first_name": {
            "type": "string"
          },
          "last_name": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "external_id": {
            "type": "string",
            "description": "Ihre eigene Kunden-ID – beim erneuten Senden wird der Kunde darüber gefunden und aktualisiert"
          }
        }
      }
    }
  }
}
