Anleitung · Schnittstelle (API)

Daten anlegen, ändern und löschen

DSGVO Server & Hosting in DE BSI Allianz für Cybersicherheit BSI Allianz für Cybersicherheit ProHunde ProHunde-Kooperation BVZ Berufsverband zertifizierter Hundetrainer BVZ-Kooperation

Daten anlegen, ändern und löschen

Schreiben geht genauso geradlinig wie Lesen. Zwei Vorkehrungen ersparen dir dabei später viel Ärger — die stehen weiter unten unter „Doppelte Datensätze verhindern“ und „Fremde Änderungen nicht überschreiben“.

1. Anlegen

POST /api/v1/contacts
Content-Type: application/json

{
  "lastname":  "Müller",
  "firstname": "Erika",
  "email":     "erika.mueller@example.de",
  "city":      "Musterstadt",
  "zip":       "12345"
}

Die Antwort hat den Status 201 und enthält den fertigen Datensatz samt seiner neuen Kennung:

{ "data": { "id": 4711, "lastname": "Müller", ... } }

Welche Felder es gibt und welche Pflicht sind, sagt dir vorher /api/v1/contacts/_schema.

2. Ändern

Mit PATCH änderst du nur die Felder, die du mitschickst. Alles andere bleibt, wie es war:

PATCH /api/v1/contacts/4711

{ "city": "Neustadt" }

PUT verhält sich wie PATCH, verlangt aber zusätzlich alle Pflichtfelder. Nicht mitgeschickte Felder bleiben auch hier stehen — die Schnittstelle leert nie stillschweigend etwas. PATCH ist fast immer richtig.

Manche Felder sind nur beim Anlegen schreibbar, danach nicht mehr — etwa der Kontakt einer Rechnung. In _schema tragen sie "immutable": true.

3. Löschen

DELETE /api/v1/contacts/4711

Das verschiebt den Datensatz in den Papierkorb. Er ist damit aus dem Weg, aber nicht weg. Zurückholen:

POST /api/v1/contacts/4711/restore

Endgültig löschen — nur für Administratoren und unwiderruflich:

DELETE /api/v1/contacts/4711?force=1

4. Doppelte Datensätze verhindern

Stell dir vor: Dein Programm schickt „Kontakt anlegen“, und die Verbindung bricht ab. Ist der Kontakt jetzt da oder nicht? Dein Programm weiß es nicht. Schickt es die Anfrage sicherheitshalber noch einmal, hast du den Kontakt womöglich zweimal.

Dagegen gibt es eine einfache Vorkehrung. Schick beim Anlegen einen frei gewählten Wert mit:

POST /api/v1/contacts
Idempotency-Key: bestellung-4711

{ "lastname": "Müller", ... }

Kommt dieselbe Anfrage ein zweites Mal, liefert die Schnittstelle die ursprüngliche Antwort zurück, statt einen zweiten Datensatz anzulegen. Der Wert wird 24 Stunden lang gemerkt.

Als Wert eignet sich alles, was den Vorgang eindeutig kennzeichnet: eine Bestellnummer, eine fortlaufende Nummer aus deinem System, oder einfach eine zufällige Kennung, die dein Programm pro Vorgang einmal erzeugt.

Nimmst du denselben Wert für einen anderen Inhalt, bekommst du einen Fehler 409 — das ist Absicht und schützt vor Verwechslungen.

5. Fremde Änderungen nicht überschreiben

Zweites Szenario: Dein Programm liest einen Kontakt, rechnet ein bisschen, und schreibt eine Minute später zurück. In der Zwischenzeit hat eine Mitarbeiterin denselben Kontakt in der Oberfläche bearbeitet. Ohne Vorkehrung überschreibt dein Programm ihre Arbeit stillschweigend.

Beim Lesen bekommst du eine Stand-Kennung in der Kopfzeile ETag:

GET /api/v1/contacts/4711

ETag: "3f8a91c2b4e07d15"

Schick sie beim Ändern als If-Match mit:

PATCH /api/v1/contacts/4711
If-Match: "3f8a91c2b4e07d15"

{ "city": "Neustadt" }

Hat inzwischen jemand anderes den Datensatz angefasst, kommt Status 412 zurück, und deine Änderung wird nicht ausgeführt. Dein Programm liest dann neu, entscheidet, und schreibt noch einmal.

Dieselbe Kennung spart beim Lesen Übertragung: Schickst du sie als If-None-Match und hat sich nichts geändert, antwortet die Schnittstelle mit 304 und ohne Daten.

6. Prüffehler verstehen

Passt eine Angabe nicht, bekommst du Status 422 und eine Liste der betroffenen Felder:

{
  "error": {
    "status": 422,
    "code": "validation_failed",
    "message": "Die übergebenen Daten sind ungültig.",
    "details": [
      { "field": "email",
        "message": "Keine gültige E-Mail-Adresse." },
      { "field": "zip",
        "message": "Zu lang (12 Zeichen, erlaubt sind 10)." },
      { "field": "lastname",
        "message": "Nachname ist ein Pflichtfeld." }
    ]
  }
}

Die Meldungen sind so geschrieben, dass du sie einem Benutzer unverändert anzeigen kannst.

Auch ein Tippfehler im Feldnamen wird gemeldet, statt stillschweigend ignoriert zu werden — sonst wunderst du dich, warum eine Angabe nicht ankommt:

{ "field": "nachname",
  "message": "Unbekanntes Feld \"nachname\". Die schreibbaren
              Felder liefert GET /api/v1/contacts/_schema." }

7. Verweise werden geprüft

Trägst du beim Tier einen Halter ein, der nicht existiert, wird das abgelehnt:

{ "field": "id_contact",
  "message": "Kontakt verweist auf \"contacts\" mit der
              Kennung 99999 — dieser Datensatz existiert
              nicht (oder liegt im Papierkorb)." }

So entstehen über die Schnittstelle keine Datensätze, die ins Leere zeigen.

8. Datumsangaben und Zahlen

Die Schnittstelle nimmt beide Schreibweisen an und gibt einheitlich zurück:

Du darfst schickenDu bekommst zurück
2026-08-17 oder 17.08.20262026-08-17
2026-08-17 14:30 oder 17.08.2026 14:302026-08-17 14:30:00
2026-08-17T12:30:00Z (mit Zeitzone)2026-08-17 14:30:00 — umgerechnet in die Zeit deiner Instanz
12.50 oder "12,50"12.5
true, 1, "ja"true

Uhrzeiten schreibst du als 14:30 oder 14:30:00.

9. Was die Schnittstelle nicht zulässt — und warum

Die Schnittstelle kennt die Regeln der Software. Eine festgeschriebene Rechnung bleibt festgeschrieben, eine stornierte Buchung storniert, eine gebuchte Zahlung gebucht — egal, welchen Schlüssel du benutzt. Solche Datensätze sind gesperrt: Ändern und Löschen beantwortet die Schnittstelle mit Status 409 und dem Code record_locked. Die Meldung sagt dir jeweils, warum und was stattdessen geht.

Das geht nichtStattdessen
Festgeschriebene Rechnung ändern oder löschenPOST /api/v1/invoices/{id}/cancel erzeugt eine Korrekturrechnung
Rechnungsnummer, Festschreibung oder Summen selbst setzenPOST /api/v1/invoices/{id}/close schreibt den Entwurf fest und vergibt alles
Position an eine festgeschriebene Rechnung hängenPositionen kommen nur an Entwürfe
Zahlung ändern oder löschenPOST /api/v1/payments/{id}/cancel bucht sie gegen
Zahlung auf einen Rechnungsentwurferst festschreiben, dann buchen
Stornierte, ausgecheckte oder abgerechnete Buchung oder Termin ändernNotizfelder bleiben änderbar; alles Weitere in der Oberfläche
Kennwort eines Kontakts setzengar nicht — Kennwörter vergibt nur die Software
E-Mails anlegen, Kassenbuch oder Kundenkonto bebuchennur lesen; diese Vorgänge laufen über die Oberfläche

Welche Bedingung einen Bereich sperrt, steht in GET /api/v1/<bereich>/_schema unter meta.locked_when; die Felder, die trotz Sperre änderbar bleiben, unter meta.writable_when_locked. Zustandsfelder wie finalized, canceled, paid, checkin oder sent sind überall nur lesbar — sie werden von der Software gesetzt, nicht von außen.

10. Eine Rechnung über die Schnittstelle stellen

Der Ablauf ist derselbe wie in der Oberfläche: Entwurf anlegen, Positionen dazu, festschreiben, Zahlung buchen.

POST /api/v1/invoices
{ "id_contact": 4711, "invoicedate": "2026-09-09", "target": "2026-09-23",
  "subject": "Rechnung September" }
→ 201, Entwurf mit invoicenumber "ENTWURF"

POST /api/v1/lineitems
{ "id_contact": 4711, "id_invoice": 9338, "servicename": "Einzelstunde",
  "servicedate": "2026-09-09", "quantity": 1,
  "net_price_item": 50, "end_price_item": 59.50,
  "net_price_overall": 50, "end_price_overall": 59.50, "taxrate": 19 }

POST /api/v1/invoices/9338/close
→ 200, Rechnungsnummer vergeben, PDF erzeugt, Rechnung gesperrt

POST /api/v1/payments
{ "id_invoice": 9338, "id_paymenttype": 1, "amount": 59.50,
  "paymentdate": "2026-09-10" }
→ 201, Rechnung steht auf „bezahlt“

Die Schnittstelle rechnet dabei den Steueranteil der Zahlung aus, weist Überzahlungen ab und setzt den Rechnungszustand (offen, teilweise bezahlt, bezahlt) — genau wie beim Buchen in der Oberfläche. Eine E-Mail an den Kunden verschickt sie nicht; der Versand bleibt der Oberfläche vorbehalten.

Einen Entwurf, den du nicht mehr brauchst, löschst du mit DELETE /api/v1/invoices/{id}. Seine Positionen bleiben als offene Positionen erhalten. Eine festgeschriebene Rechnung machst du mit POST /api/v1/invoices/{id}/cancel rückgängig: Es entsteht eine Korrekturrechnung mit der Nummer …-S, alle Positionen werden gutgeschrieben und die Zahlungen storniert.

Zeit für den Wechsel

Frage noch offen?

Wenn dir in der Anleitung etwas fehlt — schreib uns. Wir nehmen Themen aus Support-Tickets oft sofort als neue Anleitung auf.

DSGVO-konform Server in Deutschland Persönlicher Support