API-Änderungsprotokoll
API Changelog
Alle Änderungen und Verbesserungen der xoPort REST API im Überblick.
Versionen
v2.122.6 Aktuell
6. Oktober 2026Produktbewertungen exportieren
- Neu:
GET /reviews,GET /review/{reviews_id}und der BereichGET /reviews/{von}:{bis}mit dem Scopeproducts:read. Bisher lieferte die API am Produkt nur den Durchschnitt und die Anzahl der Bewertungen (products_rating,products_rating_count). - Je Bewertung:
reviews_id,products_id,products_model,reviews_rating,status,promo_status,author,verified_purchase,helpful_count,review_external_id,date_added,last_modifiedunddescriptions[]je Sprache mitreviews_title,reviews_textundreviews_reply(Antwort des Shops). - Filter:
products_id(auch als Kommaliste),status(1= freigegeben, Vorgabe;0= wartet auf Freigabe;all) undsince(angelegt oder zuletzt geändert ab). Geblättert wird wie bei den Produkten mitlimitundpage. - Keine Kundendaten:
authorist der Name, den auch die Produktseite zeigt. Kunden-ID, E-Mail und Bestellnummer gibt der Endpunkt nicht aus, nurverified_purchase. Ab Shop 4.9.153.
v2.122.5
1. Oktober 2026XML-Schnittstelle: Produktexport und Lieferanten
- Der XML-Produktexport brach mit HTTP 500 ab, sobald ein Artikel noch nicht im Schnellsuch-Index stand. Diese Artikel werden jetzt normal exportiert, der JSON-Export war nicht betroffen.
- Der XML-Produktimport gleicht den Knoten
suppliersjetzt ab, statt die Lieferanten zu löschen und neu anzulegen. Die Lieferanten-Artikelnummer bleibender Lieferanten bleibt erhalten. Ab Shop 4.9.139.
v2.122.4
30. September 2026Merkmale und Tickets
- Merkmale:
options[].costist jetzt ein anderer Name fürext_cost. Ein so geschriebener Einkaufspreis landete bisher an einer Stelle, die weder Produktseite noch Checkout noch Editor lesen. Werden beide gesendet, giltext_cost. Einkaufspreis und UVP werden als Betrag geprüft, ungültige Werte meldet die WarnungOPTION_META_INVALID. - Tickets:
DELETE /ticketsentfernt jetzt alle am Ticket hängenden Daten mit, etwa Zuständige, Abonnenten, Termin- und Projektverknüpfungen. Ab Shop 4.9.135.
v2.122.3
30. September 2026Bestellungen anlegen: Preise bei Bruttoberechnung
orders:writemittax_flag = 1: Vom Shop ermittelte Preise (recalc) und der Versand auscompute_shippingsind Nettowerte. Sie wurden bisher als Brutto gezählt, die Steuer fehlte in der Summe. Jetzt werden sie hochgerechnet. Preise, die Sie selbst senden, bleiben wie bisher brutto.- Wer
expected_totalan die zu niedrige Summe angepasst hat, erhält jetzt die WarnungTOTAL_DRIFT(mitstrict_totalsHTTP 422). - Formelaufpreise der Standardmerkmale (
apply_default_attributes) werden wie auf der Produktseite berechnet. Bisher ergab eine Formel 0 €. Formeln, die nur die Produktseite auswerten kann, melden die WarnungDEFAULT_ATTRIBUTE_FORMULA. Ab Shop 4.9.134.
v2.122.2
29. September 2026Kunden: Adressen teilweise ändern, ohne dass das Land zurückspringt
PUT /Import/JSON/customersmitaddresses[]undaddress_book_id(oder dem Objektaddress) schreibt nur noch die gesendeten Felder. Bisher setzte jedes Update ohne Land das Land auf das Shopland und die Zone auf 0. Ein reines Straßen-Update machte so aus einer österreichischen Adresse eine deutsche.- Land und Zone ändern sich nur, wenn Sie sie mitsenden. Bei einem unbekannten Land meldet die Antwort die Warnung
ADDRESS_COUNTRY. Ein Update behält dann das gespeicherte Land, eine neue Adresse erhält wie bisher das Shopland. - Ebenfalls behoben: Apostrophe wurden mit Backslash gespeichert, und zu lange Werte wurden ohne Hinweis byteweise gekürzt. Jetzt wird zeichenweise gekürzt, mit der Warnung
ADDRESS_TRUNCATED. Ziffern inentry_countrygelten nicht als Länder-ID. - Shops mit älterer Version: Senden Sie bei Adress-Updates immer das Land mit. Ab Shop 4.9.132.
v2.122.1
27. September 2026Sicherheit: Kunden- und Bestellexport ohne Passwortdaten
- Die Exporte
/customersund/orders(JSON und XML) liefern den Passwort-Hash und die Token für Passwort-Reset und Kontolöschung nicht mehr aus:customers_password,customers_password_request,customers_password_request_timeundcustomers_hashentfallen ersatzlos. - Der Kundendatensatz enthält außerdem kein
ibanund keinbicmehr. Im Bestelldatensatz bleiben beide Felder erhalten. Ab Shop 4.9.123.
v2.121.0
19. September 2026News-Import legt fehlende Sprachen an
POST /Import/JSON/newsdeskergänzt beim Anlegen jede aktive Sprache, für die kein eigener Block gesendet wurde, aus der Master-Sprache (demde-Block, sonst dem ersten gesendeten Block). Ist die DeepL-Übersetzung eingerichtet, übersetzt sie diese Sprachen beim nächsten Lauf. Bisher blieb ein nur mitdeangelegter Artikel dauerhaft einsprachig.- Geänderte Texte im verschachtelten
languages-Format werden jetzt ebenfalls neu übersetzt. Ab Shop 4.9.106.
Die Versionsnummern 2.119.1 und 2.122.0 betreffen interne Endpunkte, 2.120.0 ist noch nicht veröffentlicht.
v2.119.0
18. September 2026REST-API: immer mit Token, optional zusätzlich auf feste Adressen beschränkt
- Wichtig: Die IP-Freigabe der XML-Schnittstelle (
XML_PORT_IP_FILTER) berechtigt nicht mehr zur JSON/REST-API. REST verlangt immer einen OAuth2-Token, und es gelten dessen Scopes. Ein Client, der REST bisher ohne Token allein über eine freigegebene Adresse genutzt hat, erhält401mitreason: deny_token_required. - Neu ist die Einstellung
XOPORT_REST_IP_LISTals Zusatzschutz. Ist sie gefüllt, muss ein Aufruf von einer gelisteten Adresse kommen und einen gültigen Token tragen, sonst folgt403mitreason: deny_ip_not_listed. - Weist die API einen Aufruf ab, nennt sie den Grund im Feld
reasonund im HeaderX-XoPort-Deny-Reason. Die XML-Schnittstelle ist unverändert. Ab Shop 4.9.83.
v2.118.1
17. September 2026Tickets: keine falsche Warnung mehr für verknüpfte Termine
linked_appointmentsanPOST/PUT /Import/JSON/ticketsmeldete zusätzlich die WarnungUNKNOWN_FIELD(„will be ignored“), obwohl die Termine seit v2.43.0 angelegt werden. Die Warnung entfällt, an der Verarbeitung ändert sich nichts. Ab Shop 4.9.75.
v2.118.0
17. September 2026Tickets: Bearbeitungs-Claim
- Neuer Endpunkt
PUT /Import/JSON/ticket_claims(Scopetickets:write) zeigt an, wer gerade an einem Ticket arbeitet. Pflichtfelderticket_id,admin_idundstate(claimedoderreleased), optionalttl_minutes(Vorgabe 60, 5 bis 240),labelundforce. - Ergebnis je Datensatz in
records[].status:claimed,refreshed,taken_over,released,unchangedoderconflict. ⚠ Ein Konflikt zählt alsfailed. GET /ticketsundGET /ticket/{id}liefern die neuen Felderclaimundedit_lock(das Ticket ist gerade im Backend geöffnet), jeweilsnull, wenn nichts vorliegt.- Eine öffentliche Antwort (per API oder im Backend) und der Wechsel auf einen Schließ-Status geben den Claim automatisch frei, eine interne Notiz nicht. Der Claim ist ein Hinweis, keine Sperre, und ändert weder
ticket_date_last_modifiednoch den Verlauf. Ab Shop 4.9.73. - Die Versionsnummern v2.116.0 und v2.117.0 gehören zu Neuerungen, die mit dem nächsten Feature-Release erscheinen; sie werden dann hier nachgetragen.
v2.115.0
15. September 2026XML-Importer prüfen die Feed-Datei beim Laden
- Enthält eine Datei Zeichen, die XML 1.0 verbietet (z. B. Steuerzeichen in Beschreibungstexten), entfernen alle acht XML-Importer diese Zeichen und verarbeiten die Datei. Bisher ergab eine solche Datei 0 Datensätze, wurde trotzdem archiviert, und die Antwort meldete Erfolg.
- Lässt sich eine Datei auch danach nicht lesen, wird sie nach
xoport/xml/import/error/verschoben statt archiviert und dort wie das Archiv nach der Aufbewahrungsfrist gelöscht. - Neue Antwortfelder:
outcome(ok,partial,failed),files.failedundwarnings.invalid_xml_chars_removed.files.processed.filenamesnennt keine abgelehnten Dateien mehr. - ⚠ Scheitern alle Dateien eines Laufs, antwortet der Import mit
"state": "error"und HTTP 422. Anbindungen, die den HTTP-Status auswerten, sehen einen solchen Ausfall damit erstmals; einzelne abgelehnte Dateien erkennen Sie anoutcome: "partial". Ab Shop 4.9.65.
v2.114.0
14. September 2026Ausgeschlossene Produkte an Kupons
GET /couponsundGET /coupon/{id}liefern das neue Feldrestrictions.excluded_products: die Produkt-IDs, die aus dem Kupon nie Rabatt erhalten.- Der Ausschluss gilt zusätzlich zu allen anderen Einschränkungen und hat Vorrang vor
restrictions.products. Ein ausgeschlossener Hauptartikel schließt seine Varianten ein, eine ausgeschlossene Variante nur sich selbst. - Kupons ohne Ausschluss liefern eine leere Liste
[].
v2.113.1
14. September 2026Kupons: restrict_mode korrigiert
- ⚠
restrict_modewurde bisher verkehrt herum exportiert. Richtig ist:allow_only= nur Artikel in den gelisteten Kategorien,deny= alle außer diesen, es sei denn, der Artikel liegt zusätzlich in einer nicht gelisteten Kategorie, neudeny_strict= alle außer Artikeln, die in irgendeiner gelisteten Kategorie liegen. - Das Feld beschreibt ausschließlich
restrictions.categories.restrictions.productsundrestrictions.manufacturerssind immer Positivlisten; ist die Produktliste gefüllt, werden Kategorien und Hersteller nicht ausgewertet. - Wer das Feld seit v2.102.0 auswertet, sollte seine Zuordnung prüfen.
v2.113.0
13. September 2026Rechnungsnummer über die Schnittstelle vergeben
- Neues Feld
assign_invoice_numberanPOSTundPUT /Import/JSON/orders: mittruevergibt der Shop die nächste Nummer aus seinem Rechnungsnummernkreis. Die Nummer selbst ist nicht setzbar und danach unveränderlich. - Die Antwort meldet
invoice_number_assigned, bei Erfolg zusätzlichinvoice_id_individuellundinvoice_date. Andernfalls nenntinvoice_number_reasonden Grund (mode_disabled,already_assigned,locked), begleitet von der WarnungINVOICE_NUMBER_NOT_ASSIGNED. - Gleichzeitige Vergaben sind gegeneinander gesperrt. Bei
lockedvergibt der Shop bewusst keine Nummer statt einer doppelten – senden Sie den Aufruf dann erneut.
v2.112.0
13. September 2026Neue Kategorien mit den Vorgaben der Backend-Maske
- ⚠ Legen Sie eine Kategorie ohne
sitemapodershop_idsan, gelten jetzt dieselben Werte wie in der Backend-Maske:sitemap = 1und alle Shops als ausgeschriebene Liste. Bisher griffen die Spaltenvorgaben (keine Sitemap, keine Shopzuordnung). - Die Warnung
CATEGORY_DEFAULTS_APPLIEDnennt die gesetzten Werte. Aktualisierungen bestehender Kategorien sind nicht betroffen.
v2.111.0
13. September 2026Videos und Sendungsnummern entfernen
videos[]: einzelne Einträge mit_action: "delete"entfernen, oder mitvideos_replace: truedie gesendete Liste als vollständigen Stand übernehmen (nur auf ausdrücklichen Wunsch). Die Videodatei selbst bleibt erhalten, entfernt wird die Zuordnung.trackings[]:_action: "delete"überid_trackingoderservice_providerundcode. Eine Sendungsnummer lässt sich damit in einem Aufruf entfernen und neu anlegen.- Beide Wege prüfen, dass der Eintrag zum angegebenen Produkt bzw. zur Bestellung gehört.
v2.110.0
13. September 2026Merkmale einer bestehenden Bestellposition
products_mode: "update"nimmt jetztattributesentgegen. Die gesendete Liste ersetzt die Merkmale der Position vollständig,[]entfernt alle.- Ein abweichender Aufpreis ändert den Positionspreis nicht – die Schnittstelle warnt in diesem Fall. Soll sich der Preis ändern, stornieren Sie die Position und hängen sie neu an.
- An bereits fakturierten Bestellungen ist die Änderung gesperrt, weil Merkmale auf Rechnung und Lieferschein stehen.
v2.109.0
13. September 2026CSV-/XLS-Porter lesen und schalten
- Neu:
GET /Export/JSON/porters,/porter/{id}undPUT /Import/JSON/portersmit den Scopesporters:readundporters:write. activesetzt den Zustand (true= danach aktiv) statt ihn umzuschalten. Ohneactivewird der Aufruf abgewiesen. Beim Abschalten entfernt der Shop die erzeugte Exportdatei wie im Backend.- Der Einzelabruf liefert unter
columnsdie vollständige Spaltenzuordnung des Porters.
v2.108.0
13. September 2026Einstellungen lesen und ändern
- Neu:
GET /Export/JSON/configurationundPUT /Import/JSON/configurationmit den Scopesconfiguration:readundconfiguration:write. - ⚠ Sichtbar sind ausschließlich Schlüssel, die der Betreiber in
XOPORT_CONFIG_API_KEYSfreigibt – die Vorgabe ist leer. Zugangsdaten, Lizenz- und Sitzungseinstellungen bleiben auch mit Freigabe gesperrt. - Geändert werden nur bestehende Schlüssel, jede Änderung wird protokolliert. Die Warnung
SHOP_OVERRIDE_ACTIVEweist auf eine Domain-Überschreibung hin, die den geänderten Grundwert übersteuert.
v2.107.0
13. September 2026Bearbeiter im Bestellverlauf
user_idan einem Bestell-PUTträgt den handelnden Bearbeiter in den Verlaufseintrag ein. Übernommen wird nur eine existierende Bearbeiterkennung.customer_notifiedwird weiterhin geschrieben, die Schnittstelle meldet aber mitNO_MAIL_SENT, dass sie selbst keine Statusmail versendet.
v2.106.0
13. September 2026Produktvideos, Optionsbilder und Unterordner hochladen
- Media-Upload mit
entity_type: "product_video"(bis 100 MB) undentity_type: "option"für Optionsbilder. subfolderlegt Bilder in einem Unterordner ab (eine Ebene, Kleinbuchstaben, Ziffern,_und-).- Die Dateiendung wird aus dem erkannten Dateityp bestimmt, nicht aus dem gesendeten Dateinamen.
v2.105.0
13. September 2026Der Produkt-Export lässt sich zurückschicken
- 68 weitere Produktfelder sind schreibbar, darunter die Staffelpreise mit Mengenschwellen, die Marktplatz-Schalter, FSK 18, Sperrgut, UVP, Bonuspunkte und das Anlagedatum.
- 14 reine Lesefelder melden sich als
READONLY_FIELD, statt kommentarlos verworfen zu werden. - ⚠ Ungültige Werte (unbekannter Auswahlwert, zu langer Text, unlesbare Zahl) weisen den Datensatz ab, statt ihn halb zu schreiben. Leer gesendete Ja/Nein-Felder bleiben unverändert.
v2.104.0
13. September 2026Ersetzte Produktbilder bekommen neue Vorschaubilder
- Wird ein Bild unter demselben Dateinamen ersetzt, entfernt der Shop die zugehörigen Vorschaubilder aller Formate. Die Antwort meldet
thumbnails_removedundreplaced_existing. - Die Einträge in
videos[]werden auf unbekannte Feldnamen geprüft; mit?_strict=trueführt ein Tippfehler zu HTTP 400.
v2.103.0
13. September 2026Ticket-Abteilungen
- Neu:
GET /Export/JSON/ticket_departments(?active=),/ticket_department/{id},POST/PUT /Import/JSON/ticket_departmentsundDELETE /Delete/JSON/ticket_department/{id}. - Abteilungen sind mehrsprachig; leere Sprachen übernehmen den Namen der Standardsprache.
- Ist einer Abteilung noch ein Ticket zugeordnet, antwortet das Löschen mit
409 DEPARTMENT_IN_USE.?reassign_to={id}ordnet die Tickets vorher um,?force=1löscht trotzdem.
v2.102.0
13. September 2026Gutscheine und Kupons als JSON
- Neu:
GET /Export/JSON/couponsund/coupon/{id}mit den Filtern?code=,?type=,?active=,?kind=und?valid_on=. - Einschränkungen kommen als ID-Listen, dazu die lesbaren Felder
restrict_modeundis_credit_voucher.0bei den Einlösegrenzen bedeutet unbegrenzt. - Behoben: Name und Beschreibung eines Kupons fehlten bisher im Export.
v2.101.0
13. September 2026Der XML-Export prüft Berechtigungen
- ⚠ Ein OAuth2-Token mit eingeschränktem Scope erhält im XML-Export jetzt
403für Bereiche ohne Berechtigung:customers:read,orders:read(auch für Gutscheine),products:read,categories:read,manufacturers:read. - Anbindungen über AppKey oder IP-Freigabe sind nicht betroffen.
v2.100.0
13. September 2026Filterkonfiguration der Kategorieseiten
- Neu:
GET /Export/JSON/products_filtersund/products_filter/{fid}mit?options_id=und?categories_id=– welche Filter eine Kategorieseite anbietet. - Hinweis: 2.100.0 folgt auf 2.99.0. Vergleichen Sie Versionen mit
version_compare(), nicht als Dezimalzahl.
v2.99.0
13. September 2026Kundenexport mit Filtern und Blättern
- Neue Filter an
/customers:customers_id,customers_group_id,language_id,email,lastname,company,customers_id_extern, die Präfixfilteremail_prefix,lastname_prefix,company_prefixsowiepurchased_without_account,sort,orderundpage. - Große Kundenbestände werden in der Datenbank geblättert statt vollständig geladen.
- Ein unbrauchbarer Filterwert führt zu
400 INVALID_FILTER_VALUE, statt still ignoriert zu werden.
v2.98.0
12. September 2026Sendungsnummern, Bewertungsanfrage, Positionsfelder
trackings(Mehrzahl, wie im Export) wird angenommen. Doppelte Sendungsnummern werden übersprungen und gemeldet, ein fehlender Link wird aus dem Versanddienstleister ergänzt.rating_mailist schreibbar.products_mode: "update"ändert Felder bestehender Positionen (EK-Preis, Name, Artikelnummer, EAN, Einheit, Versandprofil, Datumsfelder). Menge, Preise und Steuersatz werden abgewiesen.
v2.97.0
12. September 2026Ticket-Anhänge entfernen, Mail erneut senden
- Neu:
DELETE /Delete/JSON/ticket_attachment/{tshid}?filename=. notify_history_idanPUT /Import/JSON/ticketssendet die Antwortmail zu einem bestehenden Verlaufseintrag erneut, ohne einen neuen anzulegen.apply_value_defaultsübernimmt beim ersten Zuordnen eines Merkmals die Vorgaben des Optionswerts (auf ausdrücklichen Wunsch, weil die Vorgaben einen Aufpreis tragen können).
v2.96.0
12. September 2026Merkmale und Optionswerte als eigene Endpunkte
- Neu:
GET /Export/JSON/products_options,/products_option/{id},/products_options_valuessowiePOST/PUT /Import/JSON/products_options. values[]ist kein vollständiger Stand: entfernt wird nur, was_action: "delete"trägt,_action: "attach"teilt einen bestehenden Wert.- ⚠ Eine unbekannte
option_idim Produktimport wird jetzt mitOPTION_NOT_FOUNDabgewiesen, statt still ein Merkmal anzulegen.
v2.95.0
12. September 2026Einzelne Verlaufseinträge löschen
- Neu:
DELETE /Delete/JSON/order_status_history/{id}undDELETE /Delete/JSON/ticket_status_history/{id}. Der Status von Bestellung bzw. Ticket wird wie in der Maske nachgeführt. - Der älteste Eintrag einer Bestellung ist geschützt (
409 FIRST_HISTORY_ENTRY).
v2.94.0
12. September 2026Lieferzeit-Profile
- Neu:
/shipping_profilesund/shipping_profile/{id}zum Lesen und Schreiben, mit Stufen, Lieferzeitspannen und Kundentexten je Sprache. - Am Produkt liefert der Export zusätzlich
shipping_profile_effective,_name,_stepund_text.
v2.93.0
12. September 2026Schnellsuche und Adressierung über die Produkt-ID
- Per Schnittstelle angelegte oder geänderte Produkte werden in die Schnellsuche aufgenommen. Der Export zeigt unter
quicksearchden Indexstand je Sprache. - Behoben: ein
PUTmitproducts_idkonnte mit HTTP 500 enden, und Adressänderungen erzeugten auf diesem Weg keine Weiterleitung.
v2.92.0
12. September 2026Optionsregeln des Konfigurators
options_rules[]am Produkt, lesend und schreibend. Fehlt das Feld, bleiben vorhandene Regeln unangetastet.- Aktive Regelblöcke werden vor dem Schreiben auf Vollständigkeit geprüft; ohne die zugehörige Lizenz wird abgewiesen.
v2.91.0
12. September 2026Statusverlauf und Belegtexte je Bestellung
- Der Bestell-Export liefert
status_history[]mit allen Verlaufseinträgen. indiv_text0bisindiv_text4(Ersatztexte je Beleg) sowieindiv_rgundindiv_ls(Dateinamen hinterlegter PDF) sind schreibbar.- Warnungen eines Bestell-
PUTerscheinen jetzt am jeweiligen Eintrag inrecords[].
v2.90.0
12. September 2026Steuerklassen und Ticket-Details
- Neu:
GET /Export/JSON/tax_classesund/tax_class/{id}mit den Steuersätzen je Steuerzone. - Der Ticketverlauf liefert die Message-ID eingegangener Mails und
ticket_event_type. - Behoben: eine reine Änderung des Videotitels endete mit HTTP 500.
v2.89.0
12. September 2026Teilerfolge werden gemeldet
- Behoben: beim Anhängen von Positionen konnte statt des Steuertitels ein Sprachschlüssel auf der Rechnung landen.
- Ohne gültige
admin_identsteht kein Ticket-Verlaufseintrag mehr. outcomemeldetpartial, wenn ein Teil des Auftrags abgelehnt wurde. Neu ist außerdem?order_id=an/tickets.
v2.88.0
12. September 2026Produkt-Reiter mehrsprachig
tabswird in der flachen, der sprachgeschachtelten und der Export-Form angenommen; der Export liefert einenlanguages-Block je Reiter.- Neue Kategorien ohne
sitemap/shop_idsmelden sich mitCATEGORY_DEFAULTS_APPLIED.
v2.87.0
12. September 2026Gebühren und Bestellreferenz schreibbar
handling_fee,transaction_fee,selling_fee,other_feeundpo_numberlassen sich perPOSTundPUTsetzen.- Beträge außerhalb des Wertebereichs und zu lange Referenzen werden abgewiesen statt gekürzt. Neu ist der Filter
?po_number=an/orders.
v2.86.0
12. September 2026Blättern und Sortieren
?sort=und?order=an/ordersund/products;?page=ist umgesetzt und wird alsstats.pagebestätigt.pagezusammen mitoffsetist ein Fehler. Eine gekapptelimit-Angabe meldet sich mitLIMIT_CAPPED.
v2.85.0
12. September 2026Sonderpreise vollständig im Export
- Sonderpreise ohne Label fehlten bisher im Export. Jetzt kommen alle Felder mit, einschließlich Kundengruppe, Zeitraum, Label und Typ.
- Neu angelegte Produkte tragen
products_last_modifiedund erscheinen damit im Änderungsfilter.
v2.84.0
12. September 2026Kategorie-Sperren schreibbar
subs_blockundtree_blocksind schreibbar. ⚠subs_blockwirkt auf Weiterleitungen und Sitemap des gesamten Kategorie-Astes.
v2.83.0
12. September 2026Alle Export-Endpunkte prüfen ihre Filter
- Unbekannte Filter werden an jedem Export-Endpunkt mit
UNKNOWN_FILTERgemeldet; mit?_strict=truebricht der Aufruf ab.
v2.82.0
12. September 2026Hersteller über den Namen
manufacturers_nameund der Herstellerblock des Exports werden aufgelöst. Unbekannte oder mehrdeutige Namen werden abgewiesen, nicht neu angelegt.- Dokumentiert, welche Daten
DELETE /productmit entfernt – oft istproducts_status = 0die bessere Wahl.
v2.81.0
12. September 2026Sonderpreise und Zusatzfelder zurückschickbar
specialwird als Liste oder Einzelobjekt angenommen,slp_valueals Label-Name.extra_fieldserscheint auch ohne Einträge als leere Liste.
v2.80.0
12. September 2026Zurückschicken ohne Datenverlust
- Behoben: Kategoriezuordnungen in der Form des Exports verschoben Produkte in Kategorie 1.
- Bildlisten werden erst geprüft und dann geschrieben; ein Hauptbild bleibt Hauptbild.
v2.79.0
12. September 2026Kategorien teilweise aktualisieren
- Ein Kategorie-
PUTbraucht den Sprachblock nicht mehr. categories_mode: "append"ergänzt Zuordnungen am Produkt; der Vollabgleich meldet entfernte Zuordnungen mitCATEGORY_ASSIGNMENTS_REPLACED.
v2.78.0
12. September 2026Kundenbezug eines Tickets per PUT
ticket_customers_orders_id,ticket_customers_id,ticket_customers_nameundticket_customers_emailwerden beimPUTgeschrieben. Die Mailadresse lässt sich nicht leeren.
v2.77.0
12. September 2026Alles oder nichts beim Import
?_strict=trueweist Produkte, Kategorien, Kunden und Bestellungen mit unbekannten Feldern vollständig ab (400 UNKNOWN_FIELD), bevor etwas geschrieben wird.
v2.76.0
12. September 2026Produkte über die ID adressieren
- Ein
PUTmitproducts_idgenügt. Mehrfach vergebene Artikelnummern werden abgewiesen statt einen beliebigen Artikel zu treffen.
v2.75.0
12. September 2026Exakte Produktfilter
- Neu:
products_modelundproducts_eanals exakte Filter,products_idals Filter;manufacturers_idwirkt jetzt. - Liefert eine einzelne ID im Mehrzahl-Pfad mehrere Datensätze, meldet sich das mit
RANGE_START_NOT_SINGLE_RECORD.
v2.74.0
12. September 2026Tickets: kein Versand mit fehlendem Anhang
- Wird ein Anhang abgewiesen, geht keine Kundenmail raus; der Kommentar bleibt gespeichert.
- Neues Antwortfeld
outcome(ok,partial,failed) als verlässliches Erfolgskriterium.
v2.73.0
12. September 2026Zahlen im JSON ohne stillen Datenverlust
- Wandelt die Zahlenerkennung Werte um (z. B. führende Nullen), meldet sich das mit
NUMERIC_CHECK_APPLIED.?numeric_check=falseliefert solche Werte unverändert als Text.
v2.72.0
12. September 2026Belegabruf ohne Nebenwirkung
- Behoben: der Abruf einer Rechnungskorrektur über
order_documentkonnte eine Korrekturnummer erzeugen. Ohne vorhandene Korrektur antwortet der Endpunkt jetzt mit409. - Nicht angewendete Felder eines Bestell-
PUTmelden sich mitFIELD_IGNORED_ON_UPDATE. Zahlart, Rechnungs- und Lieferadresse sind perPUTkorrigierbar.
v2.71.0
12. September 2026Merkmale vollständig lesen und schreiben
- ⚠ Bestehende Merkmalszuordnungen werden aktualisiert statt übersprungen; nicht gesendete Felder bleiben unverändert.
options_replacegleicht per Differenz ab – Optionsbilder, Grundpreisfaktor und EK gehen nicht mehr verloren._action: "delete"entfernt eine einzelne Zuordnung.- Neu angelegte Merkmale melden sich mit
OPTION_CREATED;options_strict_namesweist unbekannte Namen stattdessen ab.
v2.70.0
12. September 2026Löschen verlangt jetzt die Methode DELETE
- ⚠ Bitte prüfen Sie Ihre Anbindung. Die Endpunkte unter
Delete/JSON/nehmen ab sofort ausschliesslich die HTTP-MethodeDELETEan. Jede andere Methode beantwortet die Schnittstelle mit405 METHOD_NOT_ALLOWEDund dem KopfzeilenfeldAllow: DELETE– und zwar bevor irgendetwas geschieht. - Warum das nötig war: Bisher prüfte die Schnittstelle die Methode an dieser Stelle gar nicht. Ein einfacher Aufruf der Adresse im Browser, eine Linkvorschau oder ein Suchmaschinen-Roboter konnte damit einen Datensatz löschen. Es genügte, dass ein Zugangstoken einmal in einer Adresse auftauchte.
- Auswirkung in der Praxis: voraussichtlich keine. Wir haben die Zugriffsprotokolle vor der Umstellung ausgewertet – alle beobachteten Löschaufrufe verwendeten bereits
DELETE. Wenn Ihr Programm hingegenGEToderPOSTverwendet, stellen Sie es bitte um.
Fehlermeldungen sind jetzt auswertbar
- Unbekannte Adressen, ungültige Nummernbereiche und nicht vorhandene Endpunkte antworten jetzt mit JSON und dem richtigen HTTP-Statuscode (
404,400,501) statt mit einer Textzeile. Bisher meldete der Server je nach Betriebsart der PHP-Umgebung den Code200– eine Fehlerbehandlung, die den Statuscode auswertet, hielt den Aufruf also für erfolgreich. - Die Fehlerobjekte folgen dem gewohnten Aufbau:
error.code(NOT_FOUND,INVALID_RANGE,NOT_IMPLEMENTED) underror.message.
v2.69.0
7. September 2026Empfänger in Kopie (CC/BCC) sind jetzt schreibbar
- Neues Feld
receiversanPOST/PUT /ticket(s):{ mode, cc, bcc }. Bisher liessen sich die Empfänger nur lesen – pflegen ging ausschliesslich in der Maske des Shops. - Die Betriebsart
add(Vorgabe) ergänzt,replaceersetzt nur die mitgegebenen Listen,removeentfernt einzelne Adressen. Adressen werden wie im Backend geprüft; eine Liste, die nur ungültige Adressen enthält, lässt den Bestand unverändert – ein Tippfehler darf keine Empfängerliste leeren. - Der Vorgang läuft vor Kommentar und Mailversand desselben Aufrufs: „Adresse ergänzen und antworten“ geht damit in einem einzigen Aufruf.
v2.68.0
31. August 2026Hauptkategorie je Produkt
- Neues Feld
main_category_idan der Produkt-Entität. Es bestimmt, welche der mehreren Kategoriezuordnungen den Kategoriepfad in der Adresse, die kanonische Adresse, den Eintrag in der Sitemap und die Kategorieangabe in den Preisportal-Feeds liefert. - ⚠ Die Import-Semantik weicht bewusst von
categoriesab: fehlt das Feld, bleibt der Bestand unangetastet. Andernfalls würde jedes bestehende Programm, das Produkte aktualisiert, beim ersten Lauf die Hauptkategorie löschen. Der Wert0hebt die Festlegung auf. - Eine Kategorie, die dem Produkt gar nicht zugeordnet ist, wird abgewiesen und gemeldet – ein Import darf keine ins Leere zeigende Zuordnung erzeugen.
v2.67.0
26. August 2026Gewährleistungstyp ist jetzt importierbar
- Neues Feld
warranty_typeim Produkt-Import. Zulässig sindphysicalunddigital; die Schreibweise wird geheilt. Es gilt die gewohntearray_key_exists-Semantik: fehlt der Schlüssel, bleibt die Spalte unangetastet, ein leerer String leert sie. - Der Export lieferte das Feld immer schon mit – nur der Import kannte es nicht. Ein Roundtrip „exportieren, ändern, zurückschreiben“ war damit unmöglich. Dieselbe Lücke hatte v2.63.0 für die Lagerbestandsfelder geschlossen.
- ⚠ Ein unbrauchbarer Wert wird abgelehnt, nicht zurechtgebogen. Sie erhalten eine Warnung in
warnings[], der bestehende Wert bleibt stehen. Das ist Absicht: Das Feld entscheidet mit darüber, ob der Shop eine Position als Ware oder als digitalen Inhalt behandelt – und damit über die Pflichtangaben zur Gewährleistung.
Ohne API-Vertrag, aber im selben Zug behoben
- CSV-Import:
warranty_periodwird jetzt gegen die zulässigen Werte geprüft. Bisher wurde ein Freitext lediglich kleingeschrieben und dann geschrieben – verändert, aber ebenso unbrauchbar. Gleiches gilt für eine ungültige Herstellergarantie, die zuvor still geleert wurde und damit eine gepflegte Angabe löschte. - XML-Produktimport: kennt die sechs Gewährleistungs- und Garantiefelder erstmals. Liefert Ihr Feed sie nicht mit, bleiben sie unangetastet – ein reiner Bestands- oder Preisfeed ändert daran nichts.
v2.66.1
25. August 2026Gelöschte Termine verschwinden aus dem Ticket-Export
- Der Ticket-Export lieferte weich gelöschte Termine weiter aus. Wer eine Löschung über das Ticket gegengeprüft hat, hielt sie für fehlgeschlagen. Betroffen war das Feld
linked_appointments[]vonGET /Export/JSON/tickets. - Ursache war eine Auslassung, kein Tippfehler. Der Block stammt aus v2.11.0 – vier Monate bevor es den Soft-Delete für Termine gab (v2.44.0) – und bekam den Filter beim Nachziehen nie. Ein Soft-Delete lässt die Verknüpfungszeile bewusst stehen (Undelete und CalDAV-Grabstein), deshalb muss jeder Leser selbst filtern. Ticketmaske und Termin-Widget im Backend taten das seit jeher – die API widersprach damit der eigenen Oberfläche desselben Shops.
- ⚠ Verhaltensänderung ohne Anpassung auf Ihrer Seite:
linked_appointments[]kann kürzer werden, und Einträge verschwinden zwischen zwei Abrufen, ohne dass sich am Ticket etwas geändert hat. An diesem Zweig gibt es keine Grabsteine. - Grabsteine gibt es weiterhin – und vollständiger:
GET /Export/JSON/appointments?ticket_id={id}&include_deleted=1liefertdeleted_atund die Beschreibungen in allen Sprachen; für den Stapelabruf?include_deleted=1&last_modified=…zusammen mitrelationships[]. Die Tickets-Ressource bekommt bewusst keininclude_deleted: der Name wäre dort mehrdeutig, weil Tickets keinen Soft-Delete kennen. - Gleiche Ursache im Backend mitbehoben: acht Abfragen verbanden Projekte, Bestellungen und Tickets über Termine, ohne die Termintabelle zu prüfen. Ein gelöschter Termin verband weiter, und die daraus gerenderten Termin-Links liefen ins Leere.
v2.66.0
24. August 2026Importsperre für die Steuerklasse
- Neuer Sperrtyp
taxinimport_blocks. Anlass war die Buchpreisbindung: die Preissperre allein rettet einen gebundenen Ladenpreis nicht – bleibt der Nettopreis stehen und die Steuerklasse wechselt beim Import, ändert sich der Bruttopreis trotzdem, und genau der ist der gebundene Wert. Bei preisgebundenen Waren deshalb immer zusammen mitpricesetzen. - Der Typ gilt global (ohne Sprachbezug) und wird von allen Produkt-Importern ausgewertet. Im Export erscheint er automatisch, weil
import_blocks[]typ-agnostisch ist. - Begleitend im Backend: die Artikelmaske hat jetzt einen Reiter „Warenwirtschaft“ statt zweier Reiter, die dieselben Sperren steuerten und sich beim Speichern gegenseitig löschten.
v2.65.0
24. August 2026Serverseitige Filter für die Produktliste
- Bisher gab es nur
?limitund?offset. Wer eine Teilmenge brauchte, musste den kompletten Katalog seitenweise abholen – bei 62.000 Artikeln 250 Abrufe für eine Frage, die die Datenbank in einer einzigen Abfrage beantwortet. - Neue Filter:
?status=,?tax_class_id=,?categories_id=,?ean_prefix=,?model_prefix=und?last_modified=. Ein Komma trennt eine Einschlussliste (höchstens 100 Werte), mehrere Filter werden UND-verknüpft. Beispiel:?ean_prefix=978,979,977&tax_class_id=0,1&status=1findet alle kaufbaren Artikel mit Buch-EAN, die nicht im ermäßigten Steuersatz stehen. - Bewusst kein „ungleich“-Operator – den kennt die API für keine Entität. „Alles außer Steuerklasse 2“ schreibt man als Einschlussliste der übrigen Klassen; das bleibt indexfähig, statt eine zweite Abfragesprache einzuführen.
stats.totalnennt jetzt die Treffermenge. Vorher stand dort immer die Gesamtzahl der Produkte, unabhängig von der Anfrage –stats.has_morewar entsprechend falsch.- Ein unbrauchbarer Filterwert ist ein Fehler (HTTP 400), keine Warnung. Würde der Filter still verworfen, käme der ungefilterte Katalog zurück – eine Suche nach fehlerhaften Datensätzen läse daraus „nichts gefunden“. Filter an einer Einzelressource oder einem ID-Bereich werden aus demselben Grund abgewiesen.
include_inactive_productsentfällt. Der Name gehörte zur Produktliste einer Kategorie, wurde am Produkt-Export nie ausgewertet und ist durch?status=abgelöst. Er erzeugt jetzt eine Warnung statt stiller Wirkungslosigkeit.- Schema: neuer Index auf
products_last_modified(Installer und Selbstheilung; auf sehr großen Katalogen schlägt ihn stattdessen der HealthCheck vor) – ohne ihn wäre der Delta-Filter ein vollständiger Tabellendurchlauf.
v2.64.0
24. August 2026Bestelladressen dürfen leer bleiben
- Die Adressspalten einer Bestellung sind jetzt NULL-fähig (Straße, Ort und Postleitzahl je Kunden-, Liefer- und Rechnungsadresse). Marktplatz-Importe in zwei Phasen legen Abholbestellungen bereits vor der Bezahlung an – die Adresse liegt dann noch gar nicht vor und wird mit dem zweiten Abruf nachgetragen.
- Der Export liefert für solche Bestellungen
nullstatt eines leeren Strings –nullheißt „Adresse liegt noch nicht vor“, ein leerer String heißt „leer“. Firma, Adresszusatz und Bundesland waren schon immer NULL-fähig. - Korrektur: Die Kennzeichen für abweichende Rechnungs- und Lieferadresse vergleichen jetzt NULL-fest. Ein leeres Feld kippte sie vorher fälschlich auf „abweichend“.
v2.63.0
17. August 2026Lagerbestände lesbar, Hauptlager-Bestandsfelder schreibbar
- Export liefert
storages[]: Der Produkt-Export gibt die Lagerbestände jetzt mit – je Lagerzeilestorages_id,products_quantity,products_safe_quantity,products_reorder_level,products_storage_textundoptions_id. Bis v2.62.0 lieferte der JSON-Export sie gar nicht: Bestände waren per API schreib-, aber nicht lesbar, ein Roundtrip damit unmöglich. Der Feldsatz entspricht exakt dem Import, exportierte Lagerdaten sind also unverändert re-importierbar. - Ist das erweiterte Lagersystem deaktiviert, fehlt der Schlüssel ganz (nicht als leeres Array) – so unterscheidet ein Client „Funktion aus“ von „keine Lagerzeilen vorhanden“. Ausgegeben werden alle Lagerzeilen des Produkts, auch die zu inaktiven Lagern.
- Hauptlager per Import setzbar:
products_reorder_levelundproducts_safe_quantitysind jetzt auf oberster Ebene des Produkts erlaubt und schreiben das Hauptlager (dieproducts-Tabelle). Beide Spalten lieferte der Export schon immer mit, der Import verwarf sie als unbekanntes Feld – ein exportiertes Produkt ließ sich also nicht verlustfrei zurückschreiben. - Nicht verwechseln: Die gleichnamigen Felder innerhalb von
storages[]gehören zu einem Zusatzlager.storages_id: 1ist bereits das erste Zusatzlager – das Hauptlager ist kein Eintrag in der Lagerliste. - Korrektur
products_quantity: Der Bestand wird beim Import nicht mehr auf ganze Zahlen gerundet. Die Spalte erlaubt Nachkommastellen, und bei aktivierter Option „Bruchmengen im Warenkorb“ sind sie fachlich gewollt (Meterware, Gewichtsartikel) – bisher wurde aus0.5eine0, der Artikel also „nicht vorrätig“. Sichtbare Änderung für Anbindungen, die Nachkommastellen senden: der Wert kommt jetzt an, statt still zu verschwinden. - Unverändert:
storages[]bleibt ein partielles Update ohne Vollspiegel (v2.45.0); nicht mitgesendete Lagerzeilen bleiben unangetastet. CSV-/XML-Import und das Speichern im Backend schreiben weiterhin die komplette Lagerzeile.
v2.62.0
13. August 2026EU-Gewährleistungslabel (GARAN) per Schnittstelle
- Neue Produktfelder:
garan_label_enabled(0/1) gibt das EU-Gewährleistungslabel nach DVO (EU) 2025/1960 frei – verpflichtend ab 27.09.2026. Dazugaran_brand(Marke abweichend vom Katalog) undgaran_model(Modellkennung fürs Label); ein leerer String löscht den jeweiligen Wert. Die Modellkennung fasst rund 14 Zeichen – längere Werte verhindern das Rendern des Labels. - Das Label ist rechtlich verbindlich: Jede Freigabe über die Schnittstelle wird protokolliert. Die Voraussetzungen bestätigt der Shopbetreiber, nicht die API.
- Herstellergarantie jetzt mit halben Jahren:
manufacturer_guarantee_yearsist ein Dezimalwert. Werte mit Komma ("2,5") werden akzeptiert und auf die nächste niedrigere halbe Stufe gerundet, nie aufgerundet. Achtung für strenge Parser: der Export liefert jetzt"5.0"statt"5".
v2.61.0
12. August 2026Belegdokumente einer Bestellung abrufen
- Neuer Endpoint:
GET /Export/JSON/order_document/{orders_id}?type=rgliefert den fertigen Beleg als JSON mit base64-kodiertem PDF. Verfügbare Belegtypen:of(Angebot),ab(Auftragsbestätigung),rg/rgqr(Rechnung, wahlweise mit Schweizer QR-Zahlteil),ls(Lieferschein),st(Storno),pl(Packliste),prg(Proformarechnung),dr(Spendenbescheinigung) undso. Scopeorders:read. - Warum base64 statt Binärstrom: Das Feld heißt
content_base64– genau wie bei den Ticket-Anhängen aus v2.60.0. Ein Beleg lässt sich damit ohne Zwischendatei direkt an ein Ticket hängen. - Erzeugt wird genau der Beleg des Backends: Es läuft derselbe Renderer wie für die Mailanhänge, in einem eigenen Prozess und ohne Sitzung. Liegt zu einer Bestellung eine hinterlegte Rechnungsdatei vor, wird diese ausgeliefert.
- Klare Fehlerfälle: unbekannte Bestellung →
404, Rechnungsbeleg ohne Rechnungsdatum →409, unzulässiger Belegtyp →400– jeweils als sauberes JSON. - Nicht enthalten: Die
eiv_*-Typen (XRechnung, ZUGFeRD) bleiben bewusst außen vor – sie erzeugen XML statt eines PDF.
v2.60.0
11. August 2026Ticket-Anhänge jetzt auch schreibbar
- Neues Feld
attachments[]:POSTundPUT /Import/JSON/ticketsnehmen jetzt Dateien entgegen – je Eintrag einname(Dateiname inklusive Endung) undcontent_base64(Inhalt Base64-kodiert). - Bisheriges Verhalten: Anhänge waren ausschließlich lesbar (auflisten und herunterladen seit v2.9.0); geschrieben werden konnten sie nur über das Backend-Formular. Ein per API angelegtes Ticket blieb damit ohne Beleg – PDF,
.emloder Screenshot mussten von Hand nachgereicht werden. - Anhänge hängen an einem Verlaufseintrag, nicht am Ticket: ohne
ticket_commentsim selben Request entsteht kein Eintrag, an dem die Datei hängen könnte. Sie wird dann mit einer Fehlermeldung abgelehnt statt still verworfen. - Gleiche Regeln wie im Backend: identische Endungs-Allowlist, dieselbe Namenskonvention und Hash-Dedup gegen Doppelablage. Der tatsächlich vergebene Dateiname steht je Datensatz in der Antwort unter
attachments. Die Obergrenze je Datei entspricht dem/media-Endpunkt (Standard 10 MB). - Fehlertoleranz: unerlaubte Endung, ungültiges Base64 oder Überschreitung der Größe erzeugen einen Fehler je Datei – das Ticket-Update selbst bleibt erfolgreich. Bei einer öffentlichen Antwort mit Benachrichtigung gehen die Dateien mit der Kundenmail hinaus.
- Bestehende Integrationen: bleiben ohne Anpassung lauffähig – das Feld ist optional, die Erweiterung rein additiv. Scope
tickets:write.
Dokumentationskorrekturen
- Kommentarfelder richtiggestellt: Die Endpoint-Seite nannte beim Anlegen eines Tickets die Felder
initial_commentundinitial_comment_admin_id– beide existieren in der Schnittstelle nicht. Richtig sindticket_comments(Kommentartext) undadmin_id. Auch beim Aktualisieren istticket_commentsein Text, kein Array aus Objekten. Wer sich auf die alte Beschreibung gestützt hat, bekam still keinen Kommentar – und kann folglich auch keine Anhänge ablegen, weil ohne Verlaufseintrag nichts angehängt werden kann. - Öffentliche Antworten: Der Hinweis „Direkte Kundenantworten sind über die API nicht möglich“ war seit v2.25.0 überholt und wurde ersetzt. Die Flags
is_public_reply,notify_customerundappend_signaturesind jetzt in der Feldtabelle beschrieben. - Keine Codeänderung: Diese beiden Punkte betreffen ausschließlich die Dokumentation – das Verhalten der Schnittstelle ist unverändert.
v2.59.0
6. August 2026Interne Erweiterungen
- Keine Änderung an den dokumentierten Endpunkten: Diese Version erweitert ausschließlich eine interne Support-Schnittstelle von XONIC. Export, Import und DELETE verhalten sich unverändert.
- Bestehende Integrationen: bleiben ohne Anpassung lauffähig – die Versionsnummer steigt lediglich mit.
v2.58.0
6. August 2026Kombinierte Merkmalsgruppen im Produkt-Export
- Neues Feld
option_groups[]: Merkmale, die im Shop zu einer Merkmalsgruppe gekoppelt sind (typisch „Farbe + Größe“), liefert der Produkt-Export jetzt mit – inklusive der Gruppenmitglieder in Anzeigereihenfolge und je Kombination der zugehörigen Artikelnummer, EAN, Menge, Preis und Sortierung. - Bisheriges Verhalten: Gruppierte Merkmale fehlten im Export vollständig – ohne leeres Feld und ohne Hinweis. Nur ungruppierte Merkmale (
options{}) wurden ausgegeben. - Warum zwei Felder: Bei einer Merkmalsgruppe gehören Artikelnummer und EAN zur Kombination der Werte („schwarz / L“ = eine EAN), bei einem einzelnen Merkmal zum Einzelwert.
options{}bleibt daher unverändert – rein additive Erweiterung. - Unverändert: XML- und CSV-Porter geben weiterhin nur ungruppierte Merkmale aus. Der Import erwartet weiterhin das flache
options[]-Format.
v2.57.1
22. Juli 2026Bugfix: Kundenindividuelle Preise im XML-Produktimport
- XML-Produktimport: Der
customers-Block innerhalb vongroups(kundenindividuelle Preise je Produkt) wurde beim Einlesen verworfen und kam nie in der Datenbank an – die Einträge werden jetzt korrekt importiert. Die Kundenzuordnung funktioniert perid(Shop-Kunden-ID) oderexternal(WaWi-Kundennummer); unbekannte Kundennummern werden übersprungen. - Klare Regeln für unvollständige Einträge:
price 0ohne Staffelpreise legt keine Zeile an (Entfernen = Eintrag weglassen – der Import spiegelt den Kundenpreis-Bestand je Produkt voll); fehlendequantity_blocks/min_quantitywerden wie beim REST-Import mit 1 vorbelegt.
v2.57.0
18. Juli 2026Kundenrabatte & kundenindividuelle Preise
- Customers: Neues Feld
discounts[]– Kundenrabatte (das Feld „Rabatte“ der Kundenverwaltung) per API pflegen. Semantik „replace-on-present“: Ist das Feld mit Einträgen vorhanden, wird der Rabatt-Bestand des Kunden komplett ersetzt; ein leeres[]entfernt alle Rabatte; fehlt das Feld, bleiben die Rabatte unangetastet. Der Customers-Export liefertdiscountsjetzt mit (Round-Trip). - Products-Import: Neues Feld
customers_prices[]– kundenindividuelle Preise inkl. Staffelpreisen als Partial Upsert (nur mitgesendete Spalten werden geschrieben)._action: "delete"entfernt den Eintrag eines Kunden,customers_prices_replace: trueschaltet auf Vollspiegel; der Kunde wird percustomers_idodercustomers_id_extern(WaWi-Kundennummer) adressiert. - Customers-Import:
customers_id_externundcustomers_group_idsind jetzt schreibbar;PUTkann den Kunden auch ohne E-Mail übercustomers_idodercustomers_id_externadressieren (reine Rabatt-/Stammdatenpflege).
v2.54.0
14. Juli 2026Bestellungen: Die Datumsfelder – allen voran das Leistungsdatum – lassen sich jetzt auch je Position setzen. Das wird für Sammelrechnungen gebraucht, bei denen jedes Arbeitspaket ein eigenes Leistungsdatum trägt (die Belege zeigen es dann unter der jeweiligen Artikelzeile statt einmal im Belegkopf). Außerdem können per PUT /orders mit products_mode: "append" Positionen an eine bestehende Bestellung angehängt werden; die Summen werden anschließend neu berechnet. Bestellungen, die bereits als Rechnung gelten – weil eine Rechnungsnummer vergeben wurde oder der individuelle Nummernkreis deaktiviert ist – werden dabei mit ORDER_ALREADY_INVOICED abgelehnt: Eine ausgestellte Rechnung darf nachträglich nicht verändert werden. Status-, Tracking- und Datumsaktualisierungen bleiben davon unberührt.
v2.53.0
14. Juli 2026Bestellungen: Die Datumsgruppe des Bestelleditors ist jetzt per API setzbar – service_date (Leistungsdatum), estimated_service_date, shipping_date, estimated_shipping_date, invoice_date (Rechnungsdatum), invoice_payment_term_date (Zahlungsziel) sowie der Wunschtermin desired_delivery_date als Freitext. Gilt für Neuanlage (POST) und Aktualisierung (PUT); Datumsangaben werden tolerant geparst.
v2.52.0
14. Juli 2026Produktimport: Mit import_blocks lassen sich einzelne Felder eines bestehenden Produkts gezielt vor dem XML-Importer schützen – etwa wenn die deutsche Beschreibung aus der Warenwirtschaft kommt, die englische aber im Shop gepflegt wird. Das programmatische Gegenstück zum Backend-Tab „xoPort Datenschnittstelle (XML)". Geschützt werden können Name und Beschreibung (sprachbezogen) sowie sieben Preiskategorien.
v2.51.0
11. Juli 2026Produktimport: extra_fields akzeptiert Zusatzfelder jetzt wahlweise über die Feld-ID oder den Feldnamen – als Objekt oder als Liste, inklusive der Struktur, die der JSON-Export liefert (Export/Import-Round-Trip). Zuvor wurde ausschließlich die Liste mit products_extra_fields_id ausgewertet; abweichende Schreibweisen wurden ohne Hinweis verworfen. Nicht auflösbare Zusatzfelder erzeugen jetzt eine EXTRA_FIELD-Warnung, und ein Feld, das fälschlich auf oberster Ebene statt in extra_fields steht, wird in der Warnung samt passender Feld-ID benannt. Betrifft u. a. die Google-Shopping-Felder.
v2.50.0
30. Juni 2026Interne Optimierungen und Stabilitätsverbesserungen der xoPort-API.
v2.49.0
25. Juni 2026DELETE /customer_group/{id} (Scope customer_groups:delete): Löschen einer Kundengruppe mit zwei harten Schutzmechanismen – Gruppe 0 („Endkunden“) ist nicht löschbar (403), und eine Gruppe mit noch zugewiesenen Kunden wird abgelehnt (409, erst umgruppieren). Bereinigt alle abhängigen Daten (Rabatte, Specials, Gruppenpreise, Gating-Einträge).
v2.48.0
25. Juni 2026Neue Entität customer_groups (Export + Import): Kundengruppen per API enumerieren und verwalten – inkl. geparster restricted_categories_ids (Kategorie-Sperrliste der Gruppe). POST/PUT mit Enum-Validierung und ID-Härtung; POST verlangt eine explizite customers_group_id (kein AUTO_INCREMENT). Zwei neue Scopes customer_groups:read + customer_groups:write.
v2.47.0
25. Juni 2026Kategorie-Kundengruppen-Sperrliste: restricted_customer_groups jetzt auch für Kategorien (zuvor nur Produkte). Import synchronisiert customers_groups.restricted_categories, Export liefert das Feld zurück. Rekursiv: Sperrt man eine Eltern-Kategorie, werden alle aktiven Unterkategorien mitgesperrt.
v2.46.0
20. Juni 2026Media-Upload entity_type=static: neuer Wildcard-/Denylist-Modus. Mit XOPORT_MEDIA_STATIC_FOLDERS = '*' sind alle images/-Unterordner beschreibbar – außer den vom Bild-System verwalteten (source/, thumbnail/). Der Standard bleibt die strikte Freigabeliste; der Modus ist optional. Zusätzliche Härtung: strenger Ordnername-Zeichensatz, Pfad-Confinement unter images/ und ein Überschreibschutz (vorhandene Datei nur mit overwrite:true). Neue Fehlercodes PROTECTED_TARGET_FOLDER (403) und FILE_EXISTS (409).
v2.45.0
19. Juni 2026Produkt-Import storages[]: partielles Update. Pro-Lager-Bestände werden nur noch für die tatsächlich übergebenen Felder geschrieben (INSERT … ON DUPLICATE KEY UPDATE statt REPLACE). Ein Teil-Payload wie {"storages_id":1,"products_reorder_level":50} ändert damit nur den Meldebestand und setzt die übrigen Lagerspalten nicht mehr auf 0. Voll-Payloads bleiben abwärtskompatibel.
v2.44.0
18. Juni 2026Appointments API: eigenständiger Kalender-Endpoint
- Neue Top-Level-Ressource
appointmentsmit Full-CRUD:GET /appointments,POST/PUT /appointmentssowieDELETE /appointment/{id}(Soft-Delete → CalDAV-Tombstone). - Termine werden über die zentrale Termin-Logik angelegt (CalDAV-UID,
updated_at) und erscheinen sofort im Kalender der zuständigen Admins sowie in der CalDAV-Synchronisation. - Felder u. a.:
startdate(Pflicht),enddate/deadline,allday/vacation/private/done, Erinnerungen, Titel/Beschreibung/Ort (mehrsprachig),responsibilities,followers,categoriesundrelationships(Verknüpfung zu Ticket, Bestellung, Kunde oder Projekt). - Export-Filter: Zeitfenster, Zuständigkeit, Verknüpfung (z. B.
?ticket_id=) sowie?last_modified=für Delta-Sync.PUTerhält nicht übergebene Felder. - Drei neue Scopes:
appointments:read,appointments:write,appointments:delete.
v2.43.0
18. Juni 2026Tickets API: verknüpfte Termine anlegen
POST/PUT /ticketsakzeptiert jetzt das optionale Feldlinked_appointments— pro Ticket lassen sich Termine direkt mit anlegen.- Jeder Eintrag erzeugt einen Kalender-Termin und verknüpft ihn mit dem Ticket. Zuständige = die dem Ticket zugewiesenen Admins, Titel-Fallback = Ticket-Betreff.
- Pendant zum bereits vorhandenen Export-Feld
linked_appointments; benötigter Scope:tickets:write.
v2.42.0
15. Juni 2026Slider Entity-Types & News-Slider (ab Shop 4.8)
- Die Tabelle
slidernutzt ab XONIC 4.8 (alles nach Release 4.7.15) das polymorphe Spaltenpaarentity_type(category/content/news) +entity_idstattcategories_id+content_id. - Das Slider-Payload (Export & Import) führt entsprechend
entity_type+entity_id. Clients, die nochcategories_id/content_idsenden, müssen umstellen. - Neuer Typ
news: Slides lassen sich jetzt auch an News-Artikel hängen. Startseiten-Slider =entity_type=content,entity_id=0. - Export-Filter
?categories_id=/?content_id=bleiben erhalten und mappen intern auf den Entity-Typ. Bestehende Shops migrieren automatisch per Self-Heal.
v2.41.0
14. Juni 2026Media API: Projekt- & Aufgaben-Anhänge
POST /mediamitentity_type=project(bzw.task) hängt PDF-Dokumente direkt an ein xoCRM-Projekt bzw. eine Aufgabe an.- Die Datei landet im internen, zugriffsgeschützten Dateibereich des Projekts und erscheint sofort im Tab „Dateien“ — ideal für interne Dokumente wie Projektpläne.
- Pflichtfelder:
entity_id(Projekt- bzw. Aufgaben-ID, wird geprüft),file_nameund eine Quelle (file_url,file_base64oder Multipart-Upload). - Aktuell werden PDF-Dateien (
application/pdf) unterstützt; benötigter Scope:media:write.
v2.40.0
11. Juni 2026Projects API: Statuseintrag ohne Statuswechsel
PUT /projectsbzw./project_tasksmitstatus_commentschreibt jetzt auch ohne Statusänderung einen Eintrag in den Statusverlauf — ideal für Meeting-Protokolle und Arbeitsnotizen.- Aufgaben-Einträge tragen den
progress_percentmit — der Fortschrittsbalken erscheint im Verlauf.
v2.39.2
11. Juni 2026Bugfix: Einmalige Optionskosten im Frontend
- Beim Options-Import mit Vorauswahl wird jetzt auch
pre_optionin der Optionsmaske gesetzt — vorher erschien die „zzgl.“-Zeile für einmalige Optionskosten auf der Produktseite nicht.pre_optionist zusätzlich als explizites Feld im Payload erlaubt. - Core-Fix: Optionspreis ging verloren, wenn die Options-Detail-Tabelle komplett leer war.
v2.39.1
11. Juni 2026Bugfix: Produkt-Caches nach Import
- Nach jedem Produkt-Import werden die Produkt-Caches aktualisiert (Options-Vorauswahl, Preis-Labels) — wie beim Speichern im Backend.
- Vorher waren per API gesetzte Merkmals-Aufpreise und Preisänderungen im Frontend erst nach einem manuellen Nachspeichern sichtbar.
v2.39.0
11. Juni 2026Produkt-Import: Merkmale & Optionen (options[])
- Produkt-Attribute lassen sich jetzt per
POST/PUT /Import/JSON/productsanlegen: pro Eintragoption_idoderoption_name+value_idodervalue_name— fehlende Optionen/Werte werden automatisch angelegt. - Steuerfelder:
option_type(z. B. 5 = nur Anzeige),option_sort,option_required,price(Aufpreis),pre_select,status,model,ean,quantity,weight,image. - Bereits zugewiesene Kombinationen werden übersprungen (Warning
OPTION_EXISTS_SKIPPED);options_replace: truebaut die Attribute des Produkts vollständig neu auf.
v2.38.0
11. Juni 2026Produkte: Kundengruppen-Sperrliste
- Neues Feld
restricted_customer_groups[]im Produkt-Export und -Import: Gruppen-IDs, für die das Produkt gesperrt ist. - Import ersetzt die Sperrliste vollständig, wenn das Feld im Payload enthalten ist; ein leeres Array entfernt alle Sperren.
- Damit lassen sich Sichtbarkeits-Einschränkungen (z. B. nur für eine bestimmte Kundengruppe) per API von einem Produkt auf andere übertragen.
v2.37.0
11. Juni 2026Produkt-Import: Click2Call & Direktkauf-Sperre
- Zwei neue importierbare Produkt-Flags:
click2call(Anruf-Button statt Warenkorb) undnon_directcart(kein Direktkauf) — perPOST/PUT /Import/JSON/products. - Verhalten wie
non_cart/non_price: nur gesetzte Felder werden geändert.
v2.36.0
11. Juni 2026Projects API: Statuseinträge im Export
- Projekte und Aufgaben liefern jetzt
status_history[]mit — alle im Backend gepflegten Statuseinträge inkl. Kommentar (z. B. Meeting-Protokolle). - Felder pro Eintrag:
status_id+status_name,date_added,comments,progress_percent,user_id+user_name. - Rein additiv, kein neuer Scope —
projects:readbzw.project_tasks:readgenügt.
v2.35.0
11. Juni 2026Projects API: xoCRM-Projekte & Projektaufgaben
- Zwei neue Entity-Typen:
projects(xoCRM-Projekte) undproject_tasks(Projektaufgaben) — jeweils Export, Import und Delete. - Endpoints:
GET /Export/JSON/projects(Einzel/Range/Filter, optional?include_tasks=1mit eingebetteten Aufgaben),POST/PUT /Import/JSON/projects,DELETE /Delete/JSON/project/{id}— analog fürproject_tasks. - Sechs neue Scopes:
projects:read/write/delete+project_tasks:read/write/delete. - Projekte: mehrsprachige
descriptions[], Kategorien, Kunden-Zuordnung (customer_scope), Projektleiter (leader_admin_ids), Verknüpfungen zu Bestellungen/Tickets (relationships[]),is_private. - Aufgaben: Priorität (1-5), Fortschritt (0-100 %), Fälligkeit, geplante/tatsächliche Stunden, Bearbeiter-Zuweisung (
assigned_admin_ids). - Status-Handling: Validierung gegen die Status-Verwaltung, automatischer Status-History-Eintrag bei Anlage und Statuswechsel (
status_comment,admin_id). - Delete-Kaskade: Projekt-Löschung entfernt auch alle zugehörigen Aufgaben; verknüpfte Bestellungen/Tickets werden nur entkoppelt.
v2.34.0
10. Juni 2026Produkt-Import: B-Ware-Automation & neue Felder
warranty_period: Garantiezeitraum setzbar; ein leerer String""überschreibt den Standard24m.products_xoport: Marker-Feld (z. B.googleblacklist) jetzt importierbar.images[]: Zusätzliche Produktbilder per Dateiname zuweisen (ersetzt die bestehende Galerie), inkl. mehrsprachiger Alt-Texte; Array- oder Objektformat.storages[]: Pro-Lager-Bestände (Mehrlager) setzen — nur bei aktivem Mehrlager-System; der Gesamtbestandproducts_quantitybleibt separat.downloads[]: Produkt-Downloads (z. B. PDF) anlegen;d_srcverweist auf eine Datei infiles/.- Media-Upload:
POST /mediamitentity_type=downloadlädt PDF-/Dokumentdateien nachfiles/hoch.
v2.33.0
9. Juni 2026News-Autoren: Endpoint newsdesk_authors & author_id
- Neuer Endpoint
/newsdesk_authors: News-Autoren als eigene Ressource exportieren (GET /newsdesk_authors,GET /newsdesk_author/{id}) und schreiben (POST/PUT /newsdesk_authors). Scopenews:read/news:write. - Felder: sprachneutral
authors_name,authors_image,authors_email,authors_url,authors_company(Firma-Überschreibung für externe Autoren),authors_since_year,authors_status,sort_order; pro Spracheauthors_jobtitleundauthors_bio. - Verknüpfung
author_id: Der News-Im-/Export (newsdesks) enthält jetztauthor_id— Artikel lassen sich direkt mit einem Autor verbinden.
v2.32.0
7. Juni 2026Orders Import: Checkout-Parität bei Steuerzeile & Adresszusatz
- Steuerzeile pro Satz:
ot_taxwird jetzt je Steuersatz mit rate-genauem Titel im Frontend-Format geschrieben — „zzgl. USt. 19 %“ im Netto- bzw. „inkl. USt. 19 %“ im Bruttomodus (nur wennMODULE_ORDER_TOTAL_PREFIX=true) — statt der bisherigen statischen Sammelzeile „USt.:“. Die Beträge bleiben unverändert. - Neues Adressfeld
additional_address: jetzt in den erlaubten Adressfeldern — der Adresszusatz wird nachcustomers_additional_address,delivery_additional_addressundbilling_additional_addressübernommen (keinUNKNOWN_FIELD-Warning mehr).
v2.31.0
7. Juni 2026Orders Import recalc: Kategorie- & Kundenrabatt im Preis
- Der
recalc-Modus wendet jetzt zusätzlich zu Gruppenpreis und Specials auch den Kategorie-/Kundenrabatt (customers_discount+customers_groups_discount, inkl. Subkategorie-Vererbung — dieselbe Logik wie das Frontend) auf den Positionspreis an. - Der reguläre Preis wird immer rabattiert, das Special nur bei
d_special=1; der günstigere der beiden effektiven Preise gewinnt. Damit trägt die übertragene Bestellung exakt den Preis, den der Kunde auch im Checkout zahlt. - Best-effort: Bei Problemen wird die Warnung
CATEGORY_DISCOUNT_UNAVAILABLEausgegeben und ohne Rabatt gerechnet. Annahme: ein Kunde pro Request. Gäste-/Marktplatz-Bestellungen (ohnecustomers_id) bleiben unverändert.
v2.30.0
7. Juni 2026Orders Import: Dropship-Parität zum Checkout
- Show-only-Merkmale:
apply_default_attributesübernimmt jetzt auch Anzeige-Merkmale mit Vorauswahl (Options-Typ 5, z. B. „Ausführung“/„Schutzart“) inkl. signiertem Aufpreis — exakt wie sie der Checkout mitführt. Nur interne Hidden-Merkmale (Typ 6) bleiben ausgeschlossen. - EK & GTIN: Im
recalc-Modus werden Einkaufspreis (products_ek_priceausproducts_cost) und GTIN/EAN (products_ean) in die Bestellposition nachgeladen, sofern der Aufrufer nichts mitgibt. - Neues Flag
compute_shipping(Top-Level, Defaultfalse): Ohne explizitetotals.shippingwird der günstigste Versand „headless“ über den Frontend-Versand-Stack (shipping::cheapest()) für die Lieferadresse berechnet und alsot_shippinggeschrieben (Steuersatz = dominanter Produktsteuersatz). Best-effort: Fehler werfen nicht, sondern liefern die WarnungSHIPPING_AUTO_FAILEDbzw.SHIPPING_AUTO_EMPTY— die Bestellung bleibt erhalten. - Use-Case: Dropship-Übertragung (z. B. SPV → SST), bei der die Folgebestellung Merkmale, EK/GTIN und Versandkosten exakt wie eine manuelle Shop-Bestellung tragen soll.
v2.29.0
7. Juni 2026Orders Import: optionaler Versand der Bestellbestätigung
- Neues Flag
send_confirmation_email(Top-Level,true): Nach erfolgreichem Anlegen der Bestellung wird die Standard-Bestellbestätigung an den Besteller versendet — exakt wie beim normalen Checkout bzw. den Marketplace-Importern, inkl. der Kopie-Empfänger ausSEND_EXTRA_ORDER_EMAILS_TO. - Empfänger & Sprache: E-Mail aus der angelegten Bestellung (mit Validierung), Sprache aus dem Payload bzw. der Bestellung.
- Rückmeldung: Das Ergebnis steht als
confirmation_email_sent(true/false) im jeweiligen Datensatz der Antwort. Mailfehler brechen den Import nicht ab. - Default unverändert: Ohne das Flag wird keine Mail versendet (vollständig abwärtskompatibel).
v2.28.0
7. Juni 2026Orders Import: Kunden-Auto-Befüllung, SKU-Auflösung & Auto-Default-Attribute
- Rechnungsadresse aus Kundennummer: Bei
customers_id > 0und unvollständigem/fehlendembillingwird die Standard-Rechnungsadresse des Kunden (Kundenstamm + Adressbuch) übernommen — explizit gelieferte Felder gewinnen.deliverybleibt für abweichende Lieferadressen eigenständig. - SKU-Auflösung: Positionen können allein über
products_model(= SKU) +products_quantitygeliefert werden;products_idundproducts_namewerden aus dem Shop ergänzt. Unbekannte SKU → WarnungPRODUCT_MODEL_NOT_FOUND. - Auto-Default-Attribute:
apply_default_attributes: trueübernimmt je Position ohne eigene Attribute die im Shop vorausgewählten Optionswerte inkl. Aufpreis in die Bestellung. - Korrektur Mengen-Berechnung: Im
recalc-Modus wird der Netto-Stückpreis nun korrekt gespeichert (zuvor bei Menge > 1 in der Zwischensumme verdoppelt).
v2.27.1
2. Juni 2026Tickets: Öffentliche Antwort via API deckungsgleich zum Backend-Tool
- Autor-Persona: Bei
is_public_reply=trueerscheint der Verlaufseintrag unter der Ticket-Persona des handelnden Admins (Quelleadmin.ticket_settings) statt unter dem Login-Vor-/Nachnamen. Reihenfolge: optionalesticket_admin_id→admin.ticket_settings→TICKET_DEFAULT_ADMIN_ID→ Login-Name. - „Antwort eingebunden“: Das Flag
ticket_customer_notified_embeddedwird bei öffentlicher Antwort mit Mailversand gesetzt — der Antworttext ist in der Kunden-Mail eingebunden. - CC/BCC: Die CC/BCC-Empfänger des Tickets werden am Verlaufseintrag hinterlegt (Badge sichtbar) und in der Mail mitversendet.
- Mailversand-Prüfung: Der Rückgabewert des Mailversands wird ausgewertet — ein Fehlversand liefert jetzt einen Error statt eines stillen
success.
v2.26.0
1. Juni 2026Orders Export: SQL-Level-Pagination (Memory-Fix)
- Problem:
GET /Export/JSON/ordersbaute bisher den kompletten Bestell-Datensatz (inkl. Positionen, Totals, Tracking) im Arbeitsspeicher auf und schnitt erst danach via?limit/?offset— auf Shops mit vielen Bestellungen führte das zu einem PHP-Fatal „Allowed memory size exhausted“, selbst bei?limit=1. - Fix:
LIMIT/OFFSETwerden jetzt — analog zum/products-Endpoint — direkt auf dieorders_id-Query angewandt. Es wird nur noch die angeforderte Seite geladen (Default 50, Max 250 viaXOPORT_API_MAX_LIMIT). - Filter-aware:
stats.totalrespektiert aktive Filter (?status,?customer_id,?date_from/to,?since,?products_id, …); die Response trägtstats.total/limit/offset/has_more. - Unverändert: Einzel-Ressource
/order/{id}und Range/orders/{a}:{b}bleiben bewusst ohne Paging (wie bei products).
v2.25.0
30. Mai 2026Tickets: Admin-Signatur an öffentliche Antworten
- Automatische Signatur: Bei
is_public_reply: truehängt der PUT/Import/JSON/ticketsjetzt die im Backend hinterlegte Ticket-Signatur des Admins (admin_settings.signatures.tickets) automatisch an den Antworttext an — sowohl im Verlaufseintrag als auch in der Kunden-E-Mail, genau wie das Backend-Antwort-Tool. - Sprache: Standardsprache des Shops, Fallback auf die erste hinterlegte Signatur. Hat der Admin keine Signatur, bleibt der Text unverändert.
- Opt-out: optionales Flag
append_signature: false(strikt boolean) unterdrückt das Anhängen. - Wichtig für Clients: in
ticket_commentskeine eigene Signatur mehr mitschicken — sonst erscheint sie doppelt.
v2.24.0
29. Mai 2026Tickets: Öffentliche Antworten + Kunden-Notify
- Neu im Comment-Block des PUT
/Import/JSON/tickets: zwei optionale boolean-Flags pro Item —is_public_reply(true → History-Eintrag wird öffentlich) undnotify_customer(true → E-Mail an Kunden). Beide nur strikt=== truewirksam, alle anderen Werte werden ignoriert. - Default-Verhalten unverändert: ohne Flags bleibt der Kommentar intern (
ticket_internal_comment=1, keine Mail) — backward compatible mit allen v2.11.0+ Clients. - Mail-Versand nutzt das gleiche
$mail_ticket_update_with_content-Template wie das Backend-Tool (xpanel/tools-ticket-show.php), inkl. CC/BCC austicket_additional_data.receiversund Anhängen der jeweiligen History-Zeile. - Sicherheits-Default:
is_public_reply=trueohne gültigeadmin_id > 0fällt automatisch auf intern + ohne Mail zurück und gibt einenerrorzurück. Kein neuer Scope nötig (tickets:writereicht). - Use-Case: KI-Agenten oder externe Tools können jetzt Tickets nicht nur als interne Notiz, sondern als echte Kundenantwort beantworten — mit klarem Opt-in-Flag, damit „aus Versehen öffentlich" praktisch unmöglich ist.
v2.23.0
29. Mai 2026Products Single-Resource-Fix + API-Konsistenz
- Bugfix:
GET /products/{id}liefert jetzt genau ein Produkt. Zuvor griff wegen des Pluralpfad-Routings die Range-SemantikWHERE products_id >= {id}— der Client sah per.data[0]ein zufälliges Produkt aus dem Scan-Result. - BREAKING CHANGE für Categories: Das in v2.1.0 eingeführte
?id=-Query-Form bei/categories?id={id}wurde entfernt. Single-Resource gibt es ab sofort API-weit nur als Pfad-Form (/categories/{id},/products/{id}). Begründung: eine kanonische URL pro Ressource, keine Überlagerung mit Bulk-Filtern (?limit/?offset/?status/?language). - Unverändert: Range-Form
/products/100:200und Bulk-Pagination (?limit=&offset=). - Hinweis (latent): Dasselbe Pluralpfad-Routing-Verhalten existiert strukturell bei
suppliers/manufacturers/vouchers/customers/orders/newsdesks/cms/sliders— gesondertes Ticket geplant.
v2.22.0
26. Mai 2026Slider API: Promotion-Slides als neuer Entity-Typ
- Neue Endpoints:
GET /slider(s),POST/PUT /slider,DELETE /slider/{ID}. - Drei neue Scopes:
slider:read,slider:write,slider:delete(IDs 56–58). - Filter:
status,type,categories_id,content_id,language. - Nested
languages{}mittitle,description,direction,width,image,image_mobile,video,video_mobile. - Hintergrund: Promo-Slides waren bisher nur via Backend pflegbar. Der neue Endpoint erlaubt z. B. das nachträgliche Korrigieren falscher Slide-Links per
PUT /slider.
v2.21.0
19. Mai 2026Orders Import: Totals-Modi, Auto-Steuer & Drift-Check
- Auto-Derive von
customers_group_id— Kaskade Payload → Kundendatensatz → 0 (Gast). - Auto-Derive von
tax_flagauscustomers_groups.show_tax+customers_groups.tax_exempt(0=Netto, 1=Brutto, 2=Steuerfrei). Explizite Payload-Werte haben Vorrang. - Drei Totals-Modi (
totals_mode):auto(Default, Caller-Preise vertrauen),recalc(products_price+products_taxaus DB neu laden, Customer-Group- und Land-aware — ideal für Marketplace-Imports mit nur SKU + Menge),verbatim(totals.totalwird 1:1 persistiert, ideal für Refunds und historischen Re-Import). - End-to-End Drift-Check via
expected_total+strict_totals. Bei Abweichung > 0,01 €: Default = Warning, mitstrict_totals: true= atomarer Abbruch viaOrderBuilderException('TOTAL_DRIFT', 422)vor dem ersten Totals-Insert. - Whitelist-Validierung für alle Orders-Entities (
orders,order_address,order_product,order_totals,order_external_reference) — unbekannte Keys liefern dedupliziertesUNKNOWN_FIELD-Warning, analog products/customers. - PHPUnit-Suite: 17 Tests, 33 Assertions (
core/lib/classes/Tests/Order/OrderBuilderTest.php).
v2.20.0
19. Mai 2026Bestellungen-Endpoint & Generischer Webhook
- Neuer Endpoint
POST/PUT /Import/JSON/ordersmit Scopeorders:write— Bestellungen via API anlegen und aktualisieren. - Generischer Service
\\Xonic\\Order\\OrderBuilder(core/lib/classes/Order/OrderBuilder.php) — wiederverwendbar für Marketplace- und WaWi-Importer. - Typisierte Exceptions via
\\Xonic\\Order\\OrderBuilderExceptionmiterrorCode,httpCodeunddetails. - Steuerberechnung: Unterstützt Brutto- (
tax_flag=1) und Nettomodus (tax_flag=0). - Lagerbestand-Buchung via
xo_stock_change(Best-Effort: Failures werden alswarningszurückgegeben). - External-Reference-Tracking: Automatischer Eintrag in
TABLE_ORDERS_EXTERNAL_REFERENCESbei externer ID. - Marketing-Reaktion
send_webhook— generischer Outbound-Webhook mit HMAC-SHA256-Signatur und angereichertem Payload (Produkt, Bestellung, Kunde, Ticket).
v2.19.0
15. Mai 2026Media-Endpoint: Statische Asset-Uploads (entity_type=static)
- Neuer Modus
entity_type=staticim Media-Endpoint — ermöglicht das Hochladen von Branding-Assets (Logos, Schnittstellen-Bilder) ohne Datenbank-Verknüpfung. - Whitelist-Konfiguration: Erlaubte Zielordner über
XOPORT_MEDIA_STATIC_FOLDERS(Default:schnittstellen,marketplaces) — verhindert Path-Traversal-Angriffe. - Pflichtfelder:
entity_type,target_folder,file_namesowie eine Quelle (file_url,file_base64oder Multipart-Upload). - Standardverhalten: Überschreibt vorhandene Dateien (
overwrite=true). Antwort enthält den direkten Bild-Pfad. - Einschränkungen: Kein DB-Record, keine Thumbnails, kein DELETE, keine Multi-Language-Titel. PUT mit
staticwird mitSTATIC_UPDATE_NOT_SUPPORTEDabgelehnt. - Use-Case: Marketplace-Logos, Schnittstellen-Branding und statische Frontend-Assets per API verwalten.
v2.18.0
12. Mai 2026Products Import/Export: Upsells (Warenkorb-Ergänzungen)
- Neues Feld
upsellsim Products-Endpoint — analog zuxsells, aber für die „Passt dazu“-Vorschläge im Warenkorb (Tabelleproducts_upsell). - Export: pro Produkt ein Array mit
products_model,products_id(Quelle) undsort_order. Single-Product-Export liefert die Upsells des angefragten Produkts (Filter auf Quell-PID). - Import via PUT: akzeptiert ein einfaches Array von Modell-Strings (
["MODEL-A", "MODEL-B"]) oder ein Array von Objekten ([{"products_model": "MODEL-A", "sort_order": 0}]). - Replace-Semantik: bestehende Upsells werden vor dem Insert vollständig gelöscht (DELETE-then-INSERT). Self-Referenzen und unbekannte Modelle werden stillschweigend übersprungen.
- Use-Case: Befüllung der Warenkorb-Ergänzungs-Vorschläge per API — pro Produkt individuell konfigurierbar (keine globale Default-Liste).
v2.17.0
7. Mai 2026Products Import: Sonderangebote/Specials erweitert
- Vollständiger Specials-Block:
specials[]pro Produkt mitcustomers_group_id, direktem Sonderpreis oderdiscount_percent. - Zeitraum und Status:
specials_begin,specials_end(Aliasexpires_date) sowiestatus/special_status. - Angebotsbezeichnungen:
specials_price_idoder sprachabhängigesspecials_price_namemit automatischemslp-Upsert. - Pflege und Löschung: Upsert über
(products_id, customers_group_id), Entfernen viaaction: deleteoderdelete: 1. Der altespecial-Block bleibt abwärtskompatibel.
v2.16.0
29. April 2026Media API – /media-Endpoint vollständig implementiert
- Vollständiger CRUD-Support: Export (GET), Import (POST/PUT) und Delete (DELETE) für die Produktbild-Bibliothek (
products_images) — bisher waren alle Operationen501 Not ImplementedStubs. - Drei Upload-Modi:
file_url(Server-Download via cURL),file_base64(inline) undmultipart/form-data(Fieldfile). Wahl je nach Client und Dateigröße. - Validierung: MIME-Sniff (
image/jpeg|png|gif|webp), Filesize-Cap viaXOPORT_MEDIA_MAX_FILESIZE(Default 10 MB), automatische Kollisionsvermeidung, Filename-Sanitization. - Multi-Language-Titel:
descriptions[]mitlanguage_idoderlanguage_codepro Bild. PUT mitdescriptionsersetzt komplett (Full-Sync-Semantik). - Hauptbild-Promotion: Optionales
is_main=1bei POST setzt zusätzlichproducts.products_image. - Thumbnails on demand: URLs für mini/small/medium/large/xlarge werden in jeder Response zurückgegeben — physische Erzeugung erfolgt on-the-fly via
image_thumb.phpbeim ersten Aufruf. - Sicheres DELETE: Entfernt Datensatz, Description-Zeilen, Source-Datei und alle Thumbs — aber nur wenn keine andere DB-Referenz mehr auf den Dateinamen zeigt. Bulk-Delete via
?entity_id=oder{ids:[…]}. - Neue Scopes:
media:read,media:write,media:delete.
v2.15.0
23. April 2026Products Import: Family/Variants-Felder + SEO-Kollisions-Auto-Korrektur
- Family/Variants-Felder im Import:
products_family(String-Tag),products_family_type(Integer,3=Varianten-Master-Slave) undproducts_master(Integer, Master-PID oder Self-Reference) werden jetzt akzeptiert — ermöglicht Master-Slave-Gruppierungen (z.B. Paket-Varianten) via JSON-Import - Master-Slave-Workflow: Master anlegen → PID aus
records[0].products_idauslesen → zweiter PUT mitproducts_master = eigene PIDfür Self-Reference, dann Slaves zuordnen - SEO-Uniqueness-Check: Beim Import wird
seo_name(bzw. Fallbackproducts_name_as_seo) gegen alle anderen Produkte geprüft — analog zur Backend-Logik - Auto-Korrektur: Bei Slug-Kollision wird der Name automatisch zu
<slug>-<PID>korrigiert (viatep_search_new_seo()) — der Import bleibtsuccess: true - Response-Warnings: Korrekturen werden in
warnings[]mittype: "SEO_NAME_CORRECTED"inkl.requested,correctedundconflicting_with.{products_id, products_model, products_name}zurückgemeldet - Deckt zuvor bestehende Lücke: Das Backend warnt bei Slug-Kollisionen, die API ließ sie bisher silent durch und produzierte unauffindbare Produkte
v2.14.0
22. April 2026Products Import: Short-Aliases für Meta-SEO-Felder
- Neue Kurz-Aliases:
title_tag,desc_tag,keywords_tagwerden jetzt im Products-Import akzeptiert — konsistent mit der Categories-API - Internes Mapping: Die Aliases werden auf die Datenbank-Spalten
products_head_title_tag,products_head_desc_tagundproducts_head_keywords_taggemappt - Vorrang: Full column names haben Vorrang, wenn beide Varianten gesendet werden
- Rückwärtskompatibel: Bestehende Payloads mit den langen Feldnamen funktionieren unverändert
- Export: Liefert weiterhin die
products_head_*_tag-Felder (nicht die Aliases)
v2.13.0
20. April 2026SEO-History Auto-Redirects für alle Entity-Typen
- Bei Namensänderungen via JSON-Import (PUT) werden jetzt für Products (p), Categories (c), Manufacturers (m), News (n) und CMS (s) automatisch
seo_history-Einträge angelegt — alte URLs werden via 301-Redirect auf die neuen weitergeleitet - Products: Fix — greift jetzt auch bei Rename OHNE explizites
seo_name(viaproducts_name_as_seo-Auto-Regenerierung) - Manufacturers: sprachunabhängig (ein
sh_history-Eintrag, eine description-Zeile pro Sprache mit gleichem Slug) - News & CMS: sprachspezifisch (wie Categories/Products)
- Idempotent: gleiche Rename-Payload erzeugt keinen zweiten Eintrag
- Helper
persistSeoHistory()+buildSeoHistoryDeletestamp()inImportJSONextrahiert (DRY)
v2.12.0
20. April 2026Categories Productlist (Lightweight Endpoint)
- Neuer Sub-Endpoint:
GET /categories/productlist— Lightweight Mapping von Kategorien zu Produkt-IDs und Models - Query-Parameter:
?categories_id=,?status=,?include_inactive_products=,?language= - Response: Pro Kategorie
categories_id,categories_name,products_countundproducts[]Array mitid+model - Memory-effizient: Ein einziger SQL-Query statt 12+ Relations
Products SQL-Level Pagination
- Fix:
GET /productsverwendet jetzt SQL-Level Pagination (LIMIT/OFFSET direkt im Query) - Vorher: Alle Produkte + Relations in den Speicher geladen, dann
array_slice() - Nachher: Nur die angeforderte Seite wird aus der Datenbank geladen — kein Memory-Limit mehr
- Einzelabruf via
/products/{id}und Ranges unverändert
v2.11.0
13. April 2026
- Tickets Full CRUD: Import (POST/PUT) und Delete Endpoints für Tickets.
tickets:writeundtickets:deleteScopes jetzt aktiv. - Export:
linked_appointments[]: Verknüpfte CRM-Termine werden jetzt pro Ticket im Export mit ausgeliefert (Termin-ID, Start/Ende, Titel, Beschreibung, Ort). - Import POST (Create): Pflichtfelder
ticket_subject,ticket_customers_email,ticket_customers_name. Generiertticket_link_id, erstellt Upload-Verzeichnis, optionaler initialer Kommentar + Admin-Zuweisungen. - Import PUT (Update): Status/Priorität/Abteilung ändern, interne Kommentare hinzufügen (
ticket_internal_comment=1immer).admin_idist Pflichtfeld bei Kommentaren (0 = System). - Delete: Kaskadierende Löschung (status_history → admins → followers → appointments_relationships → CRM followers → Dateien → ticket).
- Scopes:
tickets:write(Import/Update),tickets:delete(Löschen) – zuvor als „geplant" markiert, jetzt voll funktionsfähig.
v2.10.0
9. April 2026
- Globale Pagination: Alle Export-Endpoints unterstützen
?limit=n&offset=n. Default-Limit 50, Hard-Cap 250 (konfigurierbar viaXOPORT_API_MAX_LIMIT/XOPORT_API_DEFAULT_LIMIT). Response enthältstats.count,stats.limit,stats.offset,stats.has_more. - Tickets – Neue Filter:
?admin_id=nfür zugewiesene Tickets (INNER JOIN auf ticket_to_admins) und?created_by_admin_id=nfür Ersteller-Filter. - Memory-Schutz: Auto-Pagination bei großen Datasets verhindert Memory-Exhaustion.
v2.9.0
8. April 2026
- Tickets API (Export): Neuer Endpoint
GET /ticketsundGET /ticket/{id}für Ticket-Export mit vollständiger Konversationshistorie, zugewiesenen Admins und Followern. - Attachment-Endpoints:
GET /ticket_attachments/{id}für Metadaten-Liste (Name, Größe, MIME-Type) undGET /ticket_attachment/{id}?file=namefür Binary-Download mit Path-Traversal-Schutz. - Query-Filter:
?status=,?priority=,?department=,?customer_id=,?type=,?date_from=&date_to=,?last_modified=,?language= - Neue Scopes:
tickets:read(implementiert),tickets:write,tickets:delete(implementiert in v2.11.0) - Meta-Daten:
ticket_statuses,ticket_priorities,ticket_departmentsin jeder Response
v2.8.1
11. März 2026
- Bugfix: Categories
last_modified: Wird jetzt bei PUT-Updates immer gesetzt — auch wenn nurlanguages-Daten (Beschreibung, Name etc.) aktualisiert werden. Zuvor wurdelast_modifiednur aktualisiert, wenn Haupttabellen-Felder (status, parent_id etc.) mitgesendet wurden. - Newsletters
ALLOWED_FIELDS:languageszur erlaubten Feldliste hinzugefügt — keinUNKNOWN_FIELD-Warning mehr bei Multi-Language Newsletter-Import.
v2.8.0
6. März 2026
- Newsletter Subscribers API: Neue Endpoints für Newsletter-Abonnenten (Export/Import/Delete) mit DOI-Support.
- Newsletter Campaigns API: Neue Endpoints für Newsletter-Kampagnen (Export/Import/Delete) mit Multi-Language-Format.
- Neue Scopes:
newsletter:read,newsletter:write,newsletter:delete,newsletters:read,newsletters:write,newsletters:delete - DOI-Support:
SHOP_NEWSLETTER_DOUBLE_OPT_INKonfiguration wird respektiert, Bestätigungs-E-Mail bei aktiviertem DOI. - Provider-Sync: Automatische Synchronisation mit externen Providern (Cleverreach, Mailchimp, Optimizely) via
xoNewsletter. - DSGVO-Compliance: Privacy-Logging bei Import/Delete, Cascade-Löschungen dokumentiert.
- Safety-Checks: Locked-Kampagnen geschützt (
409 LOCKED), versendete Newsletter nicht löschbar (409 HAS_SENT_ENTRIES). - Subscriber-Filter:
?status=confirmed|unconfirmed,?email=,?customer_id=,?language_id=,?last_modified= - Campaign-Filter:
?status=,?language_id= - Bulk-Delete: Mehrere Abonnenten per JSON-Body (by ID oder E-Mail) löschbar
v2.7.0
25. Februar 2026
- Contracts API: Neue Endpoints für Verträge/Abos (Export/Import/Delete).
- Status-Endpoint: Dedizierter
PUT /contracts/{id}/statusEndpoint für Statusänderungen. - Neue Scopes:
contracts:read,contracts:write,contracts:delete,contracts:write - Query-Filter:
?status=,?customer_id=,?product_id=,?interval=,?date_from=&date_to=,?active=1 - Nested Data: Attributes, Domains, Status-History, Orders
- Cascade-Delete: Attribute → Domains → Bestellverknüpfungen → Status-History → Vertrag
v2.6.0
24. Februar 2026
- SEO History API: Neue Endpoints für SEO-Weiterleitungen (Export/Import/Delete).
- Auto-Redirect: Bei seo_name-Änderungen im Product/Category JSON-Import werden automatisch SEO-History-Einträge erstellt (analog XML-Import).
- Neue Scopes:
seohistory:read,seohistory:write,seohistory:delete - Query-Filter:
?type=,?base_id=,?language=,?expired=1 - Bulk-DELETE: Per JSON-Body oder Query-Filter löschen
v2.5.0
23. Februar 2026
- Erweiterte Produkt-Felder: 19 neue Felder für Vertrags- und Logistik-Daten im Product Import.
- Vertragsfelder:
contract,contract_use_current_price,contract_option— Vertragsprodukte können jetzt vollständig per API angelegt werden. - Logistik-Felder:
products_cost,products_inventory_management,products_min_qty,products_max_qty,products_qty_blocks,products_base_price - Artikel-Felder:
products_sort_order,products_ean,products_free_shipping,products_image - Flags:
service,sitemap,non_cart,non_price - Zuordnungen:
shipping_profile,products_unit_id,base_unit_id
v2.4.2
19. Februar 2026
- Product Import: Nested
languages-Format: Konsistent mit Export und allen anderen Entities (Categories, Newsdesks, CMS). Akzeptiert{"languages": {"de": {...}, "en": {...}}}mit ISO-Codes oder numerischen IDs. - Auto-Fill bei INSERT: Fehlende Sprachen werden automatisch mit Master-Language-Daten befüllt.
- Flat-Format entfernt:
products_name+language_idauf Top-Level wird nicht mehr unterstützt. - Symmetrischer Roundtrip: Export → Import → Export ergibt identische Daten.
v2.4.1
19. Februar 2026
- SEO-Felder im Product Import: 7 neue Felder:
products_head_title_tag,products_head_desc_tag,products_head_keywords_tag,seo_name,products_url,products_checkout_description,products_image_title - Ermöglicht vollständigen Export→Import Roundtrip für alle Produkt-Beschreibungsfelder.
v2.4.0
6. Februar 2026
- CMS Endpoint: Neuer Entity-Typ
cmsmit vollständigen CRUD-Operationen (Export/Import/Delete). - Neue Scopes:
cms:read,cms:write,cms:delete - Safety-Checks: System-Seiten (IDs 1-999) geschützt,
content_lockrespektiert - Query-Parameter:
?status=,?module=,?language= - Multi-Language Support mit verschachteltem
languages-Format
v2.3.0
31. Januar 2026
- Suppliers CRUD: Neue Endpoints für Lieferanten (Export/Import/Delete)
- Product Export erweitert:
videos,suppliers,contenteditorFelder - Product Import erweitert:
categories_ids,groups,specials,extra_fields,badges,xsells,tabs,videos,suppliers,contenteditor - Manufacturer Import: Alle GPSR-Felder (EU + Non-EU Kontaktdaten)
- Neue Scopes:
suppliers:read/write/delete - Stubs: Marketing, Newsletter, Media Endpoints (501 Not Yet Implemented)
v2.2.0
27. Januar 2026
- Unknown Field Warnings: Response enthält jetzt ein
warningsArray für unbekannte/ignorierte Felder - Dedupliziert: Jedes unbekannte Feld erscheint nur einmal, auch bei 100+ Records im Bulk-Import
- Nested-Fields: Prüft auch
languages.*undaddresses[]Objekte - Nicht-blockierend: Request wird trotz Warnings erfolgreich verarbeitet (Postel's Law)
- Warning-Objekt:
{type, field, entity, message, first_occurrence}
v2.1.0
27. Januar 2026
- RESTful HTTP-Methoden-Trennung:
POST= nur INSERT (neue Datensätze anlegen)PUT= nur UPDATE (existierende Datensätze aktualisieren)
- Strikte Validierung: POST mit existierender ID → 409 Conflict, PUT mit unbekannter ID → 404 Not Found
- Neues Response-Feld:
recordsArray mit{index, entity_id, status}für jeden Datensatz - HTTP 405 Method Not Allowed bei falscher Methode (z.B. DELETE auf Export-Endpoint)
- Alle 8 Entity-Endpoints unterstützen POST/PUT: categories, products, customers, manufacturers, newsdesks, newsdeskcats, faq, faqcats
v2.0.3
26. Januar 2026
- DELETE Endpoints für newsdesks und newsdeskcats
- Safety-Checks: Kategorien mit Unterkategorien oder verknüpften Artikeln können nicht gelöscht werden
- Fehler-Codes:
HAS_SUBCATEGORIES,HAS_ARTICLES - Cache-Löschung nach DELETE
v2.0.2
26. Januar 2026
- Newsdesk
categories_idsim Export und Import - News-Artikel erhalten Kategorie-Zuordnungen (wie Produkte)
- Cache-Löschung nach newsdesks/newsdeskcats Import
- Newsdesks/Newsdeskcats Import mit verschachteltem
languages-Format
v2.0.1
26. Januar 2026
- Categories Import mit verschachteltem
languages-Format - Sprach-Keys als Code (
de,en) oder ID verwendbar - OAuth2 Clients Admin-UI mit Live-Suche und Sortierung
- Payload-Logging mit Request/Response-Body
v2.0.0 Breaking
26. Januar 2026
- BREAKING: OAuth2 Client Credentials (RFC 6749)
- API Keys entfernt - Migration zu OAuth2 erforderlich
- Neue Endpoints:
POST /oauth/token,GET /me - Neue Tabellen:
xoport_oauth_clients,xoport_oauth_tokens - Token-Präfix:
xoat_, Client-ID-Präfix:xoc_ - Backend: Werkzeuge → xoPort OAuth2 Clients
v1.5.0
26. Januar 2026
- FAQ Endpoints (faq/faqcategories Export/Import/Delete)
/meEndpoint für Scope-Introspection
v1.4.x
23. Januar 2026
- DELETE Endpoints für Kategorien, Produkte, Hersteller, Kunden
- Safety-Checks gegen versehentliche Löschung
- Bugfix: Double-Escaping bei HTML-Attributen behoben
v1.0.0 - v1.3.x
23. Januar 2026
- Initiale JSON API mit Export/Import
- Multi-Address-Management für Kunden
- Categories Import mit Auto-seo_name
- Language Filter, ISO-2 Country Codes
- API Key Authentifizierung (deprecated in v2.0)
Immer aktuell bleiben
Bei Breaking Changes informieren wir Sie über den Newsletter.