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
| Methode | Pfad | Beschreibung | Recht |
|---|---|---|---|
| GET | /me | Konto und Schlüsselrechte | — |
| GET | /options | Auswahlwerte (Konfiguration) und Feldliste | options:read |
| POST | /saddles | Sattel anlegen (Kurzcode, erster Chronik-Eintrag) | saddles:write |
| GET | /saddles | Eigene Sättel suchen: ?serial= ?external_id= ?short_code= ?q= ?limit= ?offset= | saddles:read |
| GET | /saddles/{id} | Sattel lesen | saddles:read |
| POST | /saddles/claim | Sattel per Kurzcode übernehmen (Hersteller-Chip → eigenes Konto, Kunde zuordnen) | saddles:write |
| PATCH | /saddles/{id} | Stammdaten ändern, Kunde zuordnen | saddles:write |
| GET | /saddles/{id}/events | Chronik lesen | events:read |
| POST | /saddles/{id}/events | Chronik-Eintrag anlegen (verifizierte Konten) | events:write |
| PATCH | /saddles/{id}/events/{event_id} | Eigenen Chronik-Eintrag ändern | events:write |
| DELETE | /saddles/{id}/events/{event_id} | Eigenen Chronik-Eintrag entfernen (archivieren) | events:write |
| GET | /customers | Eigenen Kundenstamm lesen: ?email= ?external_id= ?q= | customers:read |
| POST | /customers | Kunde anlegen oder aktualisieren (Abgleich über external_id, sonst E-Mail) | customers:write |
| PATCH | /customers/{id} | Kunde ändern | customers:write |
| GET | /public/saddles/{short_code} | Öffentlicher Sattelpass, wie beim Scan | — |
| GET | /webhooks | Eigene 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.
Fehlercodes
| MISSING_KEY / INVALID_KEY | 401 | Schlüssel fehlt, ist falsch oder widerrufen. |
| INSUFFICIENT_SCOPE | 403 | Schlüssel hat dieses Recht nicht (z. B. Einbett-Schlüssel schreibt keine Chronik). |
| ORIGIN_NOT_ALLOWED | 403 | Einbett-Schlüssel von einer nicht freigegebenen Domain verwendet. |
| NOT_VERIFIED | 403 | Konto noch nicht verifiziert – Chronik-Einträge erst danach. |
| NOT_FOUND | 404 | Sattel/Kunde nicht gefunden oder gehört nicht zu Ihrem Konto. |
| DUPLICATE_EXTERNAL_ID | 409 | Für diese external_id existiert bereits ein Sattel (details.saddle_id). |
| VALIDATION | 422 | Pflichtfeld fehlt oder Wert ungültig (details.field). |
| IDEMPOTENCY_MISMATCH | 422 | Gleicher Idempotency-Key mit anderen Daten. |
| RATE_LIMITED | 429 | Anfragen-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.created | Neuer Sattel – egal ob per API, Dashboard, App, Import oder Einbett-Formular. |
| saddle.updated | Stammdaten geändert (auch NFC-Chip beschrieben). |
| saddle.owner_changed | Kunde/Besitzer zugeordnet oder geändert. |
| transfer.accepted | Übergabe an einen neuen Besitzer angenommen. |
| saddle.stolen_reported / saddle.stolen_cleared | Diebstahl gemeldet bzw. Meldung aufgehoben. |
| event.created | Neuer Chronik-Eintrag (Arbeitsauftrag, Kontrolle, Anpassung …). |
| test.ping | Testereignis 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.
Tiefen-Link ins Dashboard
Der einfachste Weg für Systeme, die nur eine Adresse öffnen können: Das Sattelpass-Dashboard öffnet das Formular „Sattel anlegen“ vorbefüllt. Nach dem Anlegen führt ein Button zurück in Ihr System – mit Kurzcode, Sattelpass-Adresse und ID als Parameter (sattelpass_code, sattelpass_url, sattelpass_id).
https://sattelpass.com/dashboard?section=saddles&neu=1
&brand=Musterbrand&model=Elegance&seriennummer=SP-2026-0001
&external_id=ERP-48213
&return_url=https%3A%2F%2Fcrm.beispiel.de%2Fauftrag%2F48213
// oder mit dem Embed-Script: Sattelpass.dashboardLink({ brand: "…", model: "…" }, { returnUrl: "https://…" })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.