Für Entwickler und Systempartner

Sattelpass in Ihr System einbinden

Händler, Hersteller und Sattler arbeiten mit unterschiedlichen Systemen. Deshalb gibt es mehrere Wege zum Sattelpass, die alle denselben Kern nutzen: Ein per Schnittstelle angelegter Sattel ist vom Dashboard nicht zu unterscheiden, bekommt seinen Kurzcode für NFC-Chip und QR-Code und erscheint sofort in der Chronik. Ereignisse melden wir per Webhook zurück.

Zugang erhalten

API-Schlüssel und Webhook-Endpunkte richtet das Sattelpass-Team für Ihr Konto ein (Sattler- oder Herstellerkonto). Schreiben Sie kurz, welches System Sie anbinden möchten, an kontakt@sattelpass.com. Im Dashboard sehen Sie danach unter „Schnittstelle“ Ihre Schlüssel, Webhooks, Zustellungen und die letzten Anfragen. Die Nutzung ist im Tarif enthalten; per Schnittstelle angelegte Sättel zählen wie im Dashboard angelegte.

  • Server-Schlüssel (sp_live_…): für CRM, Warenwirtschaft, Backend, Skripte. Niemals in Browser- oder App-Code einbauen.
  • Einbett-Schlüssel (sp_embed_…): darf im Browser verwendet werden, ist an Ihre Domain(s) gebunden und kann nur Sättel anlegen und Auswahlwerte lesen.

REST-API

Basis-URL https://sattelpass.com/api/v1. Authentifizierung per Header Authorization: Bearer sp_live_… (alternativ X-Api-Key). Alle Antworten sind JSON (UTF-8). Fehler: { error: { code, message, details } }. Jede Antwort trägt X-Request-Id für Rückfragen.

# Sattel anlegen
curl -X POST https://sattelpass.com/api/v1/saddles \
  -H "Authorization: Bearer sp_live_…" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: bestellung-48213" \
  -d '{
    "brand": "Musterbrand",
    "model": "Elegance Dressage",
    "seriennummer": "SP-2026-004812",
    "seat_size": "17,5\"",
    "kammerweite": "W3 / 32 cm",
    "art": "Dressur",
    "external_id": "ERP-48213",
    "customer": { "email": "reiterin@example.com", "first_name": "Anna", "last_name": "Muster" },
    "created_note": "Dieser Sattel wurde ab Werk im Sattelpass erfasst."
  }'

# Antwort 201
{ "saddle": { "id": "9c1f…", "short_code": "K7PQ2XM9",
              "pass_url": "https://sattelpass.com/s/K7PQ2XM9", "external_id": "ERP-48213", … } }

# Sattel über Ihre ID oder Seriennummer finden
curl "https://sattelpass.com/api/v1/saddles?external_id=ERP-48213" -H "Authorization: Bearer sp_live_…"
curl "https://sattelpass.com/api/v1/saddles?serial=SP-2026-004812"  -H "Authorization: Bearer sp_live_…"

# Chronik-Eintrag (z. B. nach Anpassung)
curl -X POST https://sattelpass.com/api/v1/saddles/9c1f…/events \
  -H "Authorization: Bearer sp_live_…" -H "Content-Type: application/json" \
  -d '{ "event_type": "fitting", "title": "Anpassung", "public_note": "Kammerweite auf W4 angepasst." }'

Endpunkte

MethodePfadBeschreibungRecht
GET/meKonto und Schlüsselrechte—
GET/optionsAuswahlwerte (Konfiguration) und Feldlisteoptions:read
POST/saddlesSattel anlegen (Kurzcode, erster Chronik-Eintrag)saddles:write
GET/saddlesEigene Sättel suchen: ?serial= ?external_id= ?short_code= ?q= ?limit= ?offset=saddles:read
GET/saddles/{id}Sattel lesensaddles:read
POST/saddles/claimSattel per Kurzcode übernehmen (Hersteller-Chip → eigenes Konto, Kunde zuordnen)saddles:write
PATCH/saddles/{id}Stammdaten ändern, Kunde zuordnensaddles:write
GET/saddles/{id}/eventsChronik lesenevents:read
POST/saddles/{id}/eventsChronik-Eintrag anlegen (verifizierte Konten)events:write
PATCH/saddles/{id}/events/{event_id}Eigenen Chronik-Eintrag ändernevents:write
DELETE/saddles/{id}/events/{event_id}Eigenen Chronik-Eintrag entfernen (archivieren)events:write
GET/customersEigenen Kundenstamm lesen: ?email= ?external_id= ?q=customers:read
POST/customersKunde anlegen oder aktualisieren (Abgleich über external_id, sonst E-Mail)customers:write
PATCH/customers/{id}Kunde änderncustomers:write
GET/public/saddles/{short_code}Öffentlicher Sattelpass, wie beim Scan—
GET/webhooksEigene Webhook-Endpunkte und letzte Zustellungen—

Idempotenz: Senden Sie bei POST /saddles den Header Idempotency-Key (z. B. Ihre Belegnummer). Wiederholungen liefern dieselbe Antwort, ohne einen zweiten Sattel anzulegen. Zusätzlich verhindert external_id Doppelanlagen je Konto.

Limit: standardmäßig 120 Anfragen pro Minute je Schlüssel (Header X-RateLimit-Remaining). Für Massenimporte bitte kurz melden, wir erhöhen das Limit.

Maschinenlesbare Beschreibung: OpenAPI 3.1 (JSON).

Felder eines Sattels

Pflicht sind nur brand (Marke) und model (Modell). Alle Werte sind Freitext; Hersteller können unter „Konfiguration“ Auswahlwerte hinterlegen, die GET /options liefert.

seriennummerSeriennummer
brandMarke
modelModell
artArt / Disziplin
seat_sizeSitzgröße
kammerweiteKammerweite
sattel_typSattel-Typ
sattelbaumSattelbaum
kopfeisenKopfeisen
verstellbarVerstellbarkeit
aktuelle_einstellungWerkseinstellung
sattelblattSattelblattlänge
vorschnittVorschnitt / Blattart
pauschePauschen
sitzSitzform
strupfenStrupfen
polsterungPolsterung
lederLeder / Material
farbeFarbe
seller_nameVerkäufer / Vertriebspartner
external_idIhre eigene ID (eindeutig je Konto)
customer{ email, first_name, last_name, phone }
created_noteÖffentlicher Text des ersten Chronik-Eintrags

Fehlercodes

MISSING_KEY / INVALID_KEY401Schlüssel fehlt, ist falsch oder widerrufen.
INSUFFICIENT_SCOPE403Schlüssel hat dieses Recht nicht (z. B. Einbett-Schlüssel schreibt keine Chronik).
ORIGIN_NOT_ALLOWED403Einbett-Schlüssel von einer nicht freigegebenen Domain verwendet.
NOT_VERIFIED403Konto noch nicht verifiziert – Chronik-Einträge erst danach.
NOT_FOUND404Sattel/Kunde nicht gefunden oder gehört nicht zu Ihrem Konto.
DUPLICATE_EXTERNAL_ID409Für diese external_id existiert bereits ein Sattel (details.saddle_id).
VALIDATION422Pflichtfeld fehlt oder Wert ungültig (details.field).
IDEMPOTENCY_MISMATCH422Gleicher Idempotency-Key mit anderen Daten.
RATE_LIMITED429Anfragen-Limit erreicht; Retry-After beachten.

Webhooks (Rückkanal)

Sattelpass ruft Ihre HTTPS-Adresse bei Ereignissen auf – auch dann, wenn die Änderung im Dashboard, in der App oder per Import erfolgte. Ihr System antwortet mit einem 2xx-Status innerhalb von 10 Sekunden; andernfalls wiederholen wir die Zustellung mit wachsendem Abstand (1 Min, 5 Min, 30 Min, 2 Std, 12 Std). Zustellungen und Fehler sehen Sie im Dashboard unter „Schnittstelle“, wo Sie auch ein Testereignis auslösen können.

saddle.createdNeuer Sattel – egal ob per API, Dashboard, App, Import oder Einbett-Formular.
saddle.updatedStammdaten geändert (auch NFC-Chip beschrieben).
saddle.owner_changedKunde/Besitzer zugeordnet oder geändert.
transfer.acceptedÜbergabe an einen neuen Besitzer angenommen.
saddle.stolen_reported / saddle.stolen_clearedDiebstahl gemeldet bzw. Meldung aufgehoben.
event.createdNeuer Chronik-Eintrag (Arbeitsauftrag, Kontrolle, Anpassung …).
test.pingTestereignis aus dem Dashboard.
POST https://crm.beispiel.de/hooks/sattelpass
Content-Type: application/json
User-Agent: Sattelpass-Webhooks/1.0
X-Sattelpass-Event: saddle.created
X-Sattelpass-Delivery: 7c0e…            (eindeutige ID der Zustellung – für Duplikat-Erkennung)
X-Sattelpass-Timestamp: 1789487011      (Unix-Sekunden)
X-Sattelpass-Signature: v1=9f3a…        (hex HMAC-SHA256(secret, timestamp + "." + body))

{ "id": "7c0e…", "event": "saddle.created", "created_at": "2026-09-15T09:03:11Z", "attempt": 1,
  "api_version": "v1",
  "data": { "saddle": { "id": "9c1f…", "short_code": "K7PQ2XM9", "pass_url": "https://sattelpass.com/s/K7PQ2XM9",
                        "external_id": "ERP-48213", "created_via": "api", "brand": "Musterbrand", … } } }

Signatur prüfen (Node 18+, Deno, Cloudflare, Supabase Edge Functions – der Rohtext der Anfrage muss unverändert verwendet werden):

import { verifyWebhookSignature } from "https://sattelpass.com/sdk/sattelpass-api.js";

export async function handler(req) {
  const rawBody = await req.text();
  const ok = await verifyWebhookSignature({
    secret: process.env.SATTELPASS_WEBHOOK_SECRET,   // whsec_… aus dem Dashboard
    timestamp: req.headers.get("x-sattelpass-timestamp"),
    signature: req.headers.get("x-sattelpass-signature"),
    rawBody,
  });
  if (!ok) return new Response("invalid signature", { status: 401 });
  const delivery = JSON.parse(rawBody);
  // … delivery.event, delivery.data.saddle …
  return new Response("ok");
}

// PHP: hash_equals("v1=".hash_hmac("sha256", $ts.".".$raw, $secret), $sig)
// Python: hmac.compare_digest("v1="+hmac.new(secret, f"{ts}.{raw}".encode(), "sha256").hexdigest(), sig)

Einbett-Formular „Sattel anlegen“

Für Webseiten, Web-Apps und Apps ohne eigenes Backend: ein Script-Tag genügt. Das Formular läuft auf sattelpass.com, kennt die Auswahlwerte Ihres Kontos und meldet den angelegten Sattel an Ihre Seite zurück. Der Einbett-Schlüssel ist an Ihre Domain gebunden.

<div id="sattelpass"></div>
<script src="https://sattelpass.com/embed/sattelpass.js"></script>
<script>
  Sattelpass.mount({
    el: "#sattelpass",
    key: "sp_embed_…",
    prefill: { brand: "Musterbrand", model: "Elegance", seriennummer: "SP-2026-0001" },
    externalId: "ERP-48213",
    customer: true,                   // Kundenfelder anzeigen
    onCreated: (saddle) => console.log(saddle.short_code, saddle.pass_url),
    onError: (message) => console.warn(message)
  });
</script>

In React (auch Capacitor-Apps):

import { useEffect, useRef } from "react";

export function SattelpassCreate({ prefill, onCreated }) {
  const ref = useRef(null);
  useEffect(() => {
    const s = document.createElement("script");
    s.src = "https://sattelpass.com/embed/sattelpass.js";
    let widget;
    s.onload = () => {
      widget = window.Sattelpass.mount({ el: ref.current, key: import.meta.env.VITE_SATTELPASS_EMBED_KEY, prefill, onCreated });
    };
    document.body.appendChild(s);
    return () => { widget?.destroy(); s.remove(); };
  }, []);
  return <div ref={ref} />;
}

Ohne Script-Tag: iframe auf https://sattelpass.com/embed/sattel-anlegen?key=sp_embed_…&brand=… und auf Nachrichten { source: "sattelpass", type: "sattelpass:saddle-created", saddle } hören. Mit demselben Schlüssel kann eine Web-App die API auch direkt aufrufen (nur POST /saddles und GET /options).

SDK (JavaScript/TypeScript)

Ein kleiner Client ohne Abhängigkeiten, mit Typdefinitionen: sattelpass-api.js · sattelpass-api.d.ts.

import { SattelpassClient } from "https://sattelpass.com/sdk/sattelpass-api.js";

const sp = new SattelpassClient({ apiKey: process.env.SATTELPASS_API_KEY });

const existing = await sp.saddles.findByExternalId("ERP-48213");
const { saddle } = existing
  ? { saddle: existing }
  : await sp.saddles.create({ brand: "Musterbrand", model: "Elegance", external_id: "ERP-48213" },
                            { idempotencyKey: "ERP-48213" });

await sp.events.create(saddle.id, { event_type: "check", title: "Kontrolle", public_note: "Alles in Ordnung." });

In einer Supabase Edge Function (Deno) funktioniert derselbe Import; der Server-Schlüssel bleibt dort als Secret und gelangt nie in die App.

CSV/XLSX-Import ohne Programmierung

Listen aus Warenwirtschaft oder Produktion laden Sie im Dashboard unter „Werksimport“ hoch. Spalten werden automatisch erkannt, jeder Sattel bekommt seinen Kurzcode, die Codes lassen sich als CSV zurück exportieren. Auch importierte Sättel lösen Webhooks aus.

Zum Login