Docs › Sicherheit & Konto › REST-API

REST-API-Referenz

Die öffentliche REST-API von The-Y CRM ist für Server-zu-Server-Integrationen gedacht: Kontakte anlegen/lesen/aktualisieren und Ereignisse per Webhook empfangen. Authentifiziert wird mit einem API-Schlüssel.

Basis-URL (gehostet): https://crm.the-y.at/api/ext/v1 · self-host: https://<deine-domain>/api/ext/v1 · Paid-Feature

Authentifizierung

Jede Anfrage braucht deinen API-Schlüssel im Header — entweder als Bearer-Token oder als X-API-Key:

Authorization: Bearer <DEIN_API_SCHLÜSSEL>
# oder
X-API-Key: <DEIN_API_SCHLÜSSEL>

Schlüssel erstellen: In der App unter Einstellungen → Schnittstellen (unter „Erweitert“ → Verbindungen) → „API-Schlüssel" → neuer Schlüssel. Der Schlüssel wird nur einmal angezeigt — sicher speichern (in The-Y wird nur ein Hash abgelegt). Der Schlüssel bindet an deinen Mandanten.

Rechte, Ablauf und Erneuern (seit 1.1.60): Jeder Schlüssel hat eigene Rechte: contacts:read (Kontakte lesen, GET) und/oder contacts:write (Kontakte anlegen und ändern, POST/PATCH). Auf Wunsch bekommt er ein Ablaufdatum (höchstens 5 Jahre). „Erneuern“ erzeugt einen neuen Schlüssel; der alte gilt noch die gewählte Zeit (sofort, 24 Stunden, 7 oder 30 Tage). Schlüssel von vor 1.1.60 haben weiter volle Rechte ohne Ablauf, bis du „Rechte festlegen“ wählst.

Behandle den Schlüssel wie ein Passwort: nur server-seitig verwenden, nie im Browser/Frontend. Kompromittierte Schlüssel in den Integrationen widerrufen.

Konventionen

StatusBedeutung
200 / 201OK / angelegt
400Validierungsfehler (z. B. Pflichtfeld fehlt)
401Schlüssel fehlt, ist ungültig oder abgelaufen
403Feature nicht freigeschaltet (Paid), dem Schlüssel fehlt das Recht (insufficient_scope) oder das Konto ist gesperrt (tenant_suspended)
404Ressource nicht gefunden
429Rate-Limit überschritten

Kontakte

GET/contacts

Kontakte auflisten (paginiert). Optional Suche via ?q=.

# Anfrage
curl "https://crm.the-y.at/api/ext/v1/contacts?limit=20&offset=0" \
  -H "Authorization: Bearer $API_KEY"

# Antwort
{
  "data": [
    { "id": "c_123", "name": "Maria Muster", "email": "maria@example.com", "phone": "+4366012345678", "company": "ACME" }
  ],
  "hasMore": false
}

POST/contacts

Einen Kontakt anlegen. Pflichtfeld ist mindestens ein Name oder eine E-Mail.

curl -X POST "https://crm.the-y.at/api/ext/v1/contacts" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Maria Muster", "email": "maria@example.com", "phone": "+4366012345678", "company": "ACME" }'

# 201 Created
{ "data": { "id": "c_123", "name": "Maria Muster", "email": "maria@example.com" } }

GET/contacts/{id}

Einen einzelnen Kontakt lesen.

curl "https://crm.the-y.at/api/ext/v1/contacts/c_123" \
  -H "Authorization: Bearer $API_KEY"

PATCH/contacts/{id}

Einen Kontakt teilweise aktualisieren — nur die gesendeten Felder werden geändert (bestehende bleiben erhalten).

curl -X PATCH "https://crm.the-y.at/api/ext/v1/contacts/c_123" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "phone": "+4366099999999" }'
Die API ist kontakt-zentriert und wächst. Brauchst du weitere Ressourcen (Firmen, Deals, Tickets)? Schreib uns unter office@the-y.at — oder nutze für Live-Ereignisse die Webhooks unten.

Ausgehende Webhooks (Events)

Statt zu pollen, lässt du dir Ereignisse an deine URL schicken. Unter Einstellungen → Schnittstellen → „Daten senden (Webhook)" legst du Ziel-URL und Ereignisse an (z. B. contact.created, contact.updated). Das Geheimnis zum Signieren erzeugt das CRM.

Webhook-Signatur prüfen (seit 1.1.60)

Jede Sendung ist signiert. Damit prüft dein System, dass die Daten wirklich von The-Y CRM kommen und unterwegs nicht verändert wurden.

Geheimnis: Es wird beim Anlegen des Webhooks einmal angezeigt (whsec_…). Danach ist es nur noch verschlüsselt gespeichert und nirgends mehr sichtbar. Verloren? „Geheimnis erneuern“ – das alte gilt dann sofort nicht mehr.

KopfInhalt
X-TheY-TimestampZeitpunkt der Sendung in Sekunden seit 1970 (Unix-Zeit)
X-TheY-Signaturev1=<hex> – HMAC-SHA256 mit dem Geheimnis über <X-TheY-Timestamp>.<Inhalt> (Zeitstempel, ein Punkt, der unveränderte Inhalt)
X-TheY-Eventz. B. contact.created
X-TheY-Deliveryeindeutige ID der Sendung (bleibt bei Wiederholungen gleich)
X-KSCRM-Signature, X-KSCRM-Eventalt: HMAC-SHA256 nur über den Inhalt, ohne Zeitstempel. Wird noch mitgeschickt, damit bestehende Empfänger nicht brechen
Bitte umstellen: Der alte Kopf X-KSCRM-Signature fällt mit Version 1.2.0 weg. Prüfe bis dahin X-TheY-Signature wie unten.

So prüfst du: Signatur selbst berechnen und in konstanter Zeit vergleichen, und Sendungen verwerfen, deren Zeitstempel mehr als 5 Minuten von deiner Uhr abweicht (Schutz gegen erneutes Einspielen abgefangener Sendungen). Wichtig: den Inhalt roh signieren, so wie er ankommt – nicht erst als JSON einlesen und wieder ausgeben.

# Node.js (Express)
import crypto from "node:crypto";
import express from "express";

const SECRET = process.env.THEY_WEBHOOK_SECRET; // whsec_…
const app = express();

app.post("/the-y/webhook", express.raw({ type: "application/json" }), (req, res) => {
  const ts = Number(req.get("X-TheY-Timestamp"));
  const sig = (req.get("X-TheY-Signature") || "").split(",").map((s) => s.trim()).find((s) => s.startsWith("v1="))?.slice(3) || "";
  if (!Number.isInteger(ts) || Math.abs(Date.now() / 1000 - ts) > 300) return res.status(400).send("zu alt");
  const want = crypto.createHmac("sha256", SECRET).update(`${ts}.${req.body.toString("utf8")}`).digest("hex");
  const a = Buffer.from(sig, "utf8"), b = Buffer.from(want, "utf8");
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) return res.status(401).send("Signatur falsch");
  const event = JSON.parse(req.body.toString("utf8"));
  // … event.event, event.data verarbeiten
  res.sendStatus(204);
});
# PHP
<?php
$secret = getenv('THEY_WEBHOOK_SECRET'); // whsec_…
$body   = file_get_contents('php://input');
$ts     = (int)($_SERVER['HTTP_X_THEY_TIMESTAMP'] ?? 0);
$sigHdr = $_SERVER['HTTP_X_THEY_SIGNATURE'] ?? '';
$sig    = '';
foreach (explode(',', $sigHdr) as $part) { $part = trim($part); if (str_starts_with($part, 'v1=')) $sig = substr($part, 3); }
if (abs(time() - $ts) > 300) { http_response_code(400); exit('zu alt'); }
$want = hash_hmac('sha256', $ts . '.' . $body, $secret);
if (!hash_equals($want, $sig)) { http_response_code(401); exit('Signatur falsch'); }
$event = json_decode($body, true);
// … $event['event'], $event['data'] verarbeiten
http_response_code(204);

Eingehende Webhooks

Externe Systeme können über eine Token-URL Daten in The-Y anlegen/aktualisieren: POST /api/hooks/<token> (Token in den Integrationen erzeugt). Je Webhook wählst du das Zugriffs-Level: upsert (nur anlegen/aktualisieren, Löschungen ignoriert — Anti-Lock-in) oder full (inkl. Löschen).

Weiter geht's