REST-API · v1

Integriere BuildTailor 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.buildtailor.com/api/v1/me \
  -H "Authorization: Bearer sb_<dein_key>"

# 2) Templates auflisten
curl https://app.buildtailor.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.buildtailor.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.buildtailor.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.buildtailor.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.buildtailor.com/api/v1/members \
  -H "Authorization: Bearer sb_<key>"

BuildTailor · Projekte, Tickets, Attachments

Alle BT-Endpoints teilen sich Auth (Bearer sb_...), Rate-Limit (120 req/min pro Key) und Response-Envelope{ data, page?, limit?, total? }.

GET/api/v1/projects

Projekte des Workspace listen. Query: ?status=&page=&limit= (max. 100).

curl "https://app.buildtailor.com/api/v1/projects?status=active&limit=50" \
  -H "Authorization: Bearer sb_<key>"
POST/api/v1/projects

Neues Projekt anlegen. Body: name (2..200), code?, address?, status?, kind (bau|fm).

curl -X POST https://app.buildtailor.com/api/v1/projects \
  -H "Authorization: Bearer sb_<key>" \
  -H "Content-Type: application/json" \
  -d '{"name":"BV Musterstrasse 12","kind":"bau","status":"active"}'
GET/api/v1/tickets

Tickets listen. Query: ?project_id=&status=&priority=&page=&limit=. Sortierung: neueste zuerst.

curl "https://app.buildtailor.com/api/v1/tickets?project_id=<uuid>&status=offen" \
  -H "Authorization: Bearer sb_<key>"
POST/api/v1/tickets

Neues Ticket. Body: project_id, title, description?, priority?, trade?, category?, due_date?, assignee_id?, company_id?. Number wird automatisch vergeben.

curl -X POST https://app.buildtailor.com/api/v1/tickets \
  -H "Authorization: Bearer sb_<key>" \
  -H "Content-Type: application/json" \
  -d '{"project_id":"<uuid>","title":"Riss in Aussenwand EG","priority":"hoch","trade":"Rohbau"}'
PATCH/api/v1/tickets/{id}

Teil-Update. Status-Wechsel folgen der State-Machine — ungueltige Uebergaenge = 400 transition_forbidden.

curl -X PATCH https://app.buildtailor.com/api/v1/tickets/<uuid> \
  -H "Authorization: Bearer sb_<key>" \
  -H "Content-Type: application/json" \
  -d '{"status":"in_arbeit","assignee_id":"<uuid>"}'
GET/api/v1/attachments

Attachments listen. Query: ?project_id=&entity_id=&mime_prefix=&signed_url=true. signed_url=true fuegt zeitlich begrenzte Download-URLs (60s) hinzu.

curl "https://app.buildtailor.com/api/v1/attachments?project_id=<uuid>&mime_prefix=image/&signed_url=true" \
  -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.
bt.project.created
Neues Projekt in BuildTailor angelegt (via UI oder API).
bt.ticket.created
Neuer Mangel/Ticket angelegt — Payload enthaelt project_id, number, priority, assignee_id, trade.
bt.ticket.updated
Felder eines Tickets geaendert (kein Status-Wechsel) — Payload enthaelt fields=[...].
bt.ticket.status_changed
Status-Wechsel eines Tickets — Payload enthaelt from/to.
bt.attachment.uploaded
Neues Attachment (Foto etc.) an Ticket oder Kommentar.

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.