Ressourcen: quotes und sales-orders #
Angebote (Angebot) und Aufträge (Auftrag) mit Positionen. Alles
Wertbildende läuft über die EULANDA-SQL-API: Kopf-Anlage über cn_AnCre
bzw. cn_CreAf (vergibt die Belegnummer aus dem Nummernkreis), Positionen
über cn_CreAnp bzw. cn_CreAfp (macht Preisfindung, Steuer und Summen),
Wandlung über cn_TraAnAf_Typ. Summen, Steuern und Status sind read-only.
Buchen und Storno bleiben bewusst dem ERP-Anwender vorbehalten (eigene
Scopes documents:book/documents:cancel folgen später).
Endpunkte #
Für beide Belegarten identisch (/api/v1/quotes/... bzw.
/api/v1/sales-orders/...):
| Methode | Pfad | Scope | Zweck |
|---|---|---|---|
| GET | / | documents:read | Liste (Paging, q, changedSince, fields, customerMatch) |
| GET | /by-number/{number} | documents:read | Beleg über die Belegnummer (KopfNummer) |
| GET | /{id} | documents:read | Beleg über die Id |
| GET | /{id}/items | documents:read | Positionen (read-only) |
| POST | / | documents:write | Beleg anlegen, optional mit Positionen |
| POST | /{id}/items | documents:write | Einzelne Position anlegen |
| PATCH | /{id} | documents:write | Unkritische Kopf-Felder ändern |
Nur Angebote: POST /quotes/{id}/actions/convert-to-order wandelt in einen
Auftrag (Antwort: orderId, orderNumber).
?customerMatch= filtert die Liste über den Matchcode der Adresse - bei
Aktiv-Service ist das Bauvorhaben als Adresse angelegt, der Match ist die
Bauvorhaben-Nummer. DMS-Dateien der Belege: siehe DMS-Dateien.
Lieferscheine und Rechnungen (read-only) #
Dieselben vier Lese-Routen gibt es unter /api/v1/delivery-notes/... und
/api/v1/invoices/... (Scope documents:read) - bewusst ohne
Schreibwege: Lieferscheine und Rechnungen entstehen über die
EULANDA-Wandlungs-Jobs, Buchen und Storno bleiben beim ERP-Anwender.
Besondere Felder: Lieferscheine liefern trackingNumber, shippingDate,
deliveredAt, goodsValue und je Position orderItemId (Rückverweis auf
die Auftragsposition) - Positionen bewusst ohne Preise. Rechnungen liefern
isCredit (Gutschrift), dunningLevel, paidAmount, balance (offener
Saldo) und dueDate; je Position deliveryNoteItemId als Rückverweis.
Invoke-RestMethod 'http://localhost:8100/api/v1/invoices?balance=0&limit=5' -Headers $h
Invoke-RestMethod 'http://localhost:8100/api/v1/delivery-notes/by-number/2021500123' -Headers $h
Invoke-RestMethod 'http://localhost:8100/api/v1/invoices/57/items' -Headers $h
curl.exe -H "Authorization: Bearer %KEY%" "http://localhost:8100/api/v1/invoices?limit=5&fields=id,number,name,grossTotal,balance"
curl.exe -H "Authorization: Bearer %KEY%" "http://localhost:8100/api/v1/delivery-notes/by-number/2021500123"
curl.exe -H "Authorization: Bearer %KEY%" "http://localhost:8100/api/v1/invoices/57/items"
Anlegen #
Body für POST: customerId oder customerMatch (Pflicht, die Adresse
muss existieren), optional deliveryAddressId, buyerOrderNo, object,
items sowie weitere schreibbare Kopf-Felder (preText, postText,
info, Termine). Jede Position braucht articleId oder articleNumber
(der Artikel muss existieren) und quantity. Fehlende Stammdaten ergeben
422 REFERENCE_NOT_FOUND - die API legt nie stillschweigend Stammdaten an.
Eine übergebene buyerOrderNo wird auf Dubletten geprüft (409
DOC_DUPLICATE; skipDuplicateCheck: true erzwingt die Anlage).
Idempotenz (wichtig für Abrechnungsläufe) #
Jeder POST akzeptiert den Header Idempotency-Key. Derselbe Key mit
demselben Body liefert die gespeicherte Antwort erneut
(X-Idempotency-Replay: true) statt einen zweiten Beleg zu erzeugen;
derselbe Key mit anderem Body ergibt 409 IDEMPOTENCY_MISMATCH.
Empfehlung für Sync-Clients wie EulandaXtrack: fachlichen Schlüssel als Key
verwenden (z.B. xtrack-abrechnung-2026-07-baustelle-4711).
Beispiele #
Angebot mit Positionen anlegen:
$h = @{ Authorization = "Bearer $key"; 'Idempotency-Key' = 'quote-2026-07-18-demo' }
$body = @{
customerMatch = 'EULANDA'
object = 'API-Demo Bauvorhaben'
items = @(
@{ articleNumber = '1100'; quantity = 2 }
@{ articleId = 2; quantity = 1 }
)
} | ConvertTo-Json -Depth 4
Invoke-RestMethod 'http://localhost:8100/api/v1/quotes' -Method Post -Headers $h -ContentType 'application/json' -Body $body
curl.exe -X POST -H "Authorization: Bearer %KEY%" -H "Idempotency-Key: quote-2026-07-18-demo" -H "Content-Type: application/json" -d "{ \"customerMatch\": \"EULANDA\", \"object\": \"API-Demo Bauvorhaben\", \"items\": [ { \"articleNumber\": \"1100\", \"quantity\": 2 } ] }" "http://localhost:8100/api/v1/quotes"
Angebot lesen und in einen Auftrag wandeln:
Invoke-RestMethod 'http://localhost:8100/api/v1/quotes/by-number/100123' -Headers $h
Invoke-RestMethod 'http://localhost:8100/api/v1/quotes/57/items' -Headers $h
Invoke-RestMethod 'http://localhost:8100/api/v1/quotes/57/actions/convert-to-order' -Method Post -Headers $h
curl.exe -H "Authorization: Bearer %KEY%" "http://localhost:8100/api/v1/quotes/by-number/100123"
curl.exe -H "Authorization: Bearer %KEY%" "http://localhost:8100/api/v1/quotes/57/items"
curl.exe -X POST -H "Authorization: Bearer %KEY%" "http://localhost:8100/api/v1/quotes/57/actions/convert-to-order"
Aufträge eines Bauvorhabens und Position nachtragen:
Invoke-RestMethod 'http://localhost:8100/api/v1/sales-orders?customerMatch=2412V0117' -Headers $h
$item = @{ articleNumber = '1100'; quantity = 8 } | ConvertTo-Json
Invoke-RestMethod 'http://localhost:8100/api/v1/sales-orders/172/items' -Method Post `
-Headers ($h + @{ 'Idempotency-Key' = 'xtrack-2026-07-baustelle-0117' }) `
-ContentType 'application/json' -Body $item
curl.exe -H "Authorization: Bearer %KEY%" "http://localhost:8100/api/v1/sales-orders?customerMatch=2412V0117"
curl.exe -X POST -H "Authorization: Bearer %KEY%" -H "Idempotency-Key: xtrack-2026-07-baustelle-0117" -H "Content-Type: application/json" -d "{ \"articleNumber\": \"1100\", \"quantity\": 8 }" "http://localhost:8100/api/v1/sales-orders/172/items"
Fehlercodes dieser Ressourcen #
| HTTP | Code | Bedeutung |
|---|---|---|
| 404 | NOT_FOUND | Kein Beleg zum Schlüssel |
| 409 | DOC_DUPLICATE | Bestellnummer existiert bereits |
| 409 | IDEMPOTENCY_MISMATCH | Idempotency-Key mit anderem Body wiederverwendet |
| 422 | REFERENCE_NOT_FOUND | Kunde bzw. Artikel existiert nicht |
| 422 | VALIDATION_ITEM_INVALID | Position ohne Artikel oder ohne gültige Menge |
Belegfluss bis zur Rechnung #
Teillieferung: POST /sales-orders/{id}/delivery-notes mit Body
{ "items": [ { "itemId": 1780, "quantity": 1.5 } ] } liefert
Teilmengen je Position (ohne Body: Volllieferung). Rechnung:
POST /delivery-notes/{id}/invoices (einzeln) bzw.
POST /invoices/from-delivery-notes mit { "deliveryNoteIds": [...] }
als Sammelrechnung mehrerer Lieferscheine desselben Kunden.
Drei Direktgutschrift-Fälle (Scope documents:cancel):
POST /invoices/{id}/actions/credit mit mode = newOrder
(Gutschrifts-Auftrag Typ 12, keine SN), reopenDeliveryNotes
(Lieferscheine wieder berechenbar) oder reopenOrder (negative
Lieferscheine, Auftrag ins Weitererfassen - danach korrigieren und neu
berechnen). Der Zahlungsausgleich zwischen Rechnung und Gutschrift
läuft automatisch. Dazu POST /invoices/{id}/actions/cancel
(klassisches Storno: löscht die Rechnung, Lieferscheine wieder offen)
und POST /sales-orders/{id}/actions/reopen.
PDF-Ausgabe #
GET /{quotes|sales-orders|delivery-notes|invoices}/{id}/pdf rendert
den Beleg headless über ReportXtools als application/pdf-Download;
?form= wählt das Formular, ohne Angabe gilt das Standard-Formular
des Bereichs (IsDefault in der Formular-Registry).
GET /{entity}/reports listet die Formulare mit isDefault.
Voraussetzung: Udl in der Serverkonfiguration (sonst 501
PDF_RENDERER_UNAVAILABLE).