REST-API · v1

Integriere AcademyDNA in Minuten

REST-Endpunkte mit Bearer-Token-Auth + signierte Outbound-Webhooks. cURL-, JavaScript- und Python-Beispiele inklusive — und Live-Test direkt aus der Doku.


Quickstart

Drei Schritte vom Account zum ersten erfolgreichen Aufruf.

  1. 1
    API-Key erstellen
    Unter Einstellungen → Integrations einen neuen Schlüssel anlegen. Das Plaintext-Secret wird einmalig angezeigt.
  2. 2
    Request senden
    Authorization-Header setzen und einen GET-Request gegen /api/v1/me schießen.
  3. 3
    Webhooks abonnieren
    Optional: Webhook-URL eintragen und Events wählen. Wir signieren jeden Versand per HMAC-SHA256.
# 1) Verifizieren, dass dein Key tickt
curl https://app.example.com/api/v1/me \
  -H "Authorization: Bearer sb_<dein_key>"

# 2) Templates auflisten
curl https://app.example.com/api/v1/templates?limit=10 \
  -H "Authorization: Bearer sb_<dein_key>"

Authentifizierung

Alle Endpunkte erwarten einen Bearer-Token im Authorization-Header.

Beim Anlegen eines API-Keys bekommst du einen Plaintext-Token im Format sb_<prefix>_<secret>. Der Server speichert nur den SHA-256-Hash — du musst den Token sicher aufbewahren.

Authorization: Bearer sb_<prefix>_<secret>
  • read GET auf Templates, Members, Workspace-Metadaten.
  • write Reserviert für zukünftige POST/PUT/DELETE-Endpunkte (Templates, Invites).

Endpunkte

Alle Endpunkte unter /api/v1. JSON-Responses, paginiert via limit-Parameter.

Logge dich ein, um Endpunkte direkt aus der Doku zu testen.
GET/api/v1/me

Gibt das aktive Tenant + Scope-Info des API-Keys zurück. Perfekt für eine 'API-Key gültig?'-Probe.

curl https://app.example.com/api/v1/me \
  -H "Authorization: Bearer sb_<key>"
Beispiel-Response
{
  "tenant": {
    "id": "f9c8…",
    "name": "Acme GmbH",
    "slug": "acme",
    "subscription_tier": "Trial",
    "created_at": "2026-…"
  },
  "api_key": { "id": "8a2b…", "scopes": ["read"] }
}
GET/api/v1/templates

Listet alle Mail-Templates des Workspaces. Optional: ?limit=1-100 und ?category=Onboarding|Transactional|Marketing|System|Custom.

curl "https://app.example.com/api/v1/templates?limit=50&category=Onboarding" \
  -H "Authorization: Bearer sb_<key>"
Beispiel-Response
{
  "data": [
    {
      "id": "ab12…",
      "name": "Willkommens-Mail",
      "category": "Onboarding",
      "default_locale": "de-DE",
      "subject": "Willkommen bei {{workspace_name}}…",
      "variables": [
        { "name": "first_name", "label": "Vorname", "example": "Anna" }
      ],
      "is_default": true,
      "updated_at": "2026-…"
    }
  ],
  "count": 1
}
GET/api/v1/templates/{id}

Detail-View eines einzelnen Templates inklusive aller Locale-Übersetzungen (Subject + Markdown-Body).

curl https://app.example.com/api/v1/templates/ab12… \
  -H "Authorization: Bearer sb_<key>"
GET/api/v1/members

Listet alle Workspace-Mitglieder mit Rolle, Beitrittsdatum, E-Mail und Anzeigename.

curl https://app.example.com/api/v1/members \
  -H "Authorization: Bearer sb_<key>"

Webhooks

Outbound POST-Requests an deinen Endpunkt bei wichtigen Workspace-Events.

Jeder Versand trägt eine HMAC-Signatur im X-SaaSBase-Signature Header, identisch zum Stripe-Format:

X-SaaSBase-Signature: t=<unixSeconds>,v1=<hmac-sha256-hex>

Signierter Payload ist <unixSeconds>.<rawBody>

Verfügbare Events

Subscribe pro Webhook gezielt nur die Events, die dich interessieren — oder '*' für alle.

EventWann?
invite.created
Beim Anlegen einer neuen Einladung im Workspace.
invite.accepted
Wenn jemand die Einladung annimmt und Member wird.
invite.revoked
Wenn ein Owner/Admin die Einladung widerruft.
member.role_changed
Wenn die Rolle eines Members geändert wird.
template.created
Wenn ein neues Mail-Template angelegt wurde.
template.updated
Wenn ein Template gespeichert wurde (Meta oder Inhalt).
template.deleted
Wenn ein Template gelöscht wurde.

Signatur verifizieren

Im Receiver: Header parsen, HMAC neu berechnen, mit timingSafeEqual vergleichen. Timestamp-Drift > 5 Min verwerfen (Replay-Schutz).

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(",").map(kv => kv.split("=")));
  const t = parseInt(parts.t, 10);
  if (Math.abs(Math.floor(Date.now() / 1000) - t) > 300) return false;
  const expected = createHmac("sha256", secret)
    .update(`${t}.${rawBody}`).digest("hex");
  const a = Buffer.from(expected, "hex");
  const b = Buffer.from(parts.v1, "hex");
  return a.length === b.length && timingSafeEqual(a, b);
}

Fehlercodes

Standard-HTTP-Codes. Body bei Fehlern: {"error": "<message>"}.

StatusMeaningHint
200OKRequest erfolgreich.
400Bad RequestUngültige Parameter oder Body.
401UnauthorizedBearer-Token fehlt, ungültig oder widerrufen. Auch: fehlender Scope.
404Not FoundRessource existiert nicht oder gehört nicht zu deinem Tenant.
500Server ErrorUnerwarteter Fehler. Hilf uns bitte mit Support-Ticket.

Bereit zum Loslegen?

Hol dir deinen ersten API-Key in 30 Sekunden — und integriere ohne Discovery-Call.