# Konfigurations-Deeplinks Source: https://dokumentation.websale.de/admin-interface/konfigurations-deeplinks Direktlinks zu einzelnen Konfigurationsknoten des WEBSALE Admin Interface: URL-Schema und vollständige Referenz aller Knoten je Bereich. Über einen Konfigurations-Deeplink springen Sie direkt zu einem bestimmten [Konfigurationsknoten](/konfiguration) im Admin Interface, ohne sich zuvor durch die Menüstruktur klicken zu müssen. Rufen Sie die URL im Browser auf, öffnet das Admin Interface unmittelbar den passenden Konfigurationsknoten. Das Admin Interface erreichen Sie grundsätzlich unter `https://www..de/admin` (siehe [Admin-Interface-Übersicht](/admin-interface)). Das Grundprinzip des URL-Zugriffs ist zusätzlich in der [Konfigurations-Übersicht](/konfiguration) beschrieben; diese Seite bündelt die vollständige Knoten-Referenz. ## Aufbau eines Deeplinks Ein Deeplink folgt stets folgendem Schema:
Die feste Konfigurations-Basis `.../admin/config/` und dahinter der Bezeichner des Konfigurationsknotens: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https:///admin/config/ ``` **Beispiel**
Der Knoten `payment.payment` wird direkt so aufgerufen: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https:///admin/config/payment.payment ``` Ersetzen Sie `` durch die Domain Ihres Shops bzw. Subshops. Der Knotenname wird unverändert angehängt. In den Tabellen unten ist der jeweils fertige Deeplink bereits mit diesem Schema angegeben. Der Direktaufruf per URL ist derzeit ein **temporärer Workaround**, solange viele Konfigurationen noch über „Konfiguration per Code“ bereitgestellt werden und keine eigene klickbare Oberfläche im Admin Interface besitzen. Sobald die betreffenden Konfigurationen regulär über die Benutzeroberfläche verfügbar sind, behält WEBSALE sich vor, diese Aufruflogik **jederzeit zu deaktivieren**. Für einen Teil der Knoten ist der Deeplink derzeit der einzige Weg. Die Knoten unterhalb von `actions` werden in der Konfigurationsübersicht nicht als eigene Gruppe angeboten. Der Knoten `inquiry.form` wird stattdessen über den Service *Anfragen* gepflegt. ## Konfigurationsknoten im Überblick Die folgende Referenz listet alle Konfigurationsknoten, gruppiert nach Bereich, samt fertigem Deeplink. Über die Bereichslinks gelangen Sie zur ausführlichen Dokumentation des jeweiligen Konfigurationsbereichs. ### accounts – Benutzerkonten Benutzerkonten:
Registrierung, Login, Passwortregeln, Auto-Login sowie Adress- und Zahlungsdaten.
Details: [accounts-Konfiguration](/konfiguration/accounts-benutzerkonten). | Konfigurationsknoten | Deeplink | | -------------------------------- | ------------------------------------------------------------------- | | `accounts.account` | `https:///admin/config/accounts.account` | | `accounts.accountRestrictions` | `https:///admin/config/accounts.accountRestrictions` | | `accounts.addressField` | `https:///admin/config/accounts.addressField` | | `accounts.addressFieldsSettings` | `https:///admin/config/accounts.addressFieldsSettings` | | `accounts.addressPoolSeparation` | `https:///admin/config/accounts.addressPoolSeparation` | | `accounts.autoLogin` | `https:///admin/config/accounts.autoLogin` | | `accounts.bankInfoField` | `https:///admin/config/accounts.bankInfoField` | | `accounts.creditCardField` | `https:///admin/config/accounts.creditCardField` | | `accounts.customAddressField` | `https:///admin/config/accounts.customAddressField` | | `accounts.watchListField` | `https:///admin/config/accounts.watchListField` | ### actions – Fehlertexte & E-Mails Shopaktionen:
Fehlertexte, Fehlercodes und E-Mail-Vorlagen. Reihenfolge wie in der Konfiguration.
Diese Knoten werden in der Konfigurationsübersicht nicht angeboten, der Deeplink ist hier der reguläre Weg.
Details: [actions-Konfiguration](/konfiguration/actions-fehlertexte-e-mails). | Konfigurationsknoten | Deeplink | | --------------------------------------------- | -------------------------------------------------------------------------------- | | `actions.acceptInvitation` | `https:///admin/config/actions.acceptInvitation` | | `actions.accountActivate` | `https:///admin/config/actions.accountActivate` | | `actions.accountActivateConfirm` | `https:///admin/config/actions.accountActivateConfirm` | | `actions.accountDelete` | `https:///admin/config/actions.accountDelete` | | `actions.accountDisplayNameUpdate` | `https:///admin/config/actions.accountDisplayNameUpdate` | | `actions.accountMemberCreate` | `https:///admin/config/actions.accountMemberCreate` | | `actions.accountMemberDelete` | `https:///admin/config/actions.accountMemberDelete` | | `actions.accountMemberPrivilegeGroupCreate` | `https:///admin/config/actions.accountMemberPrivilegeGroupCreate` | | `actions.accountMemberPrivilegeGroupDelete` | `https:///admin/config/actions.accountMemberPrivilegeGroupDelete` | | `actions.accountMemberUpdate` | `https:///admin/config/actions.accountMemberUpdate` | | `actions.accountRegister` | `https:///admin/config/actions.accountRegister` | | `actions.addCommentToBasket` | `https:///admin/config/actions.addCommentToBasket` | | `actions.addressCreate` | `https:///admin/config/actions.addressCreate` | | `actions.addressDelete` | `https:///admin/config/actions.addressDelete` | | `actions.addressUpdate` | `https:///admin/config/actions.addressUpdate` | | `actions.askForBasketVerification` | `https:///admin/config/actions.askForBasketVerification` | | `actions.backInStockActivate` | `https:///admin/config/actions.backInStockActivate` | | `actions.backInStockDeactivate` | `https:///admin/config/actions.backInStockDeactivate` | | `actions.basketItemAdd` | `https:///admin/config/actions.basketItemAdd` | | `actions.basketItemDelete` | `https:///admin/config/actions.basketItemDelete` | | `actions.basketItemUpdate` | `https:///admin/config/actions.basketItemUpdate` | | `actions.blacklistAdd` | `https:///admin/config/actions.blacklistAdd` | | `actions.checkoutAccountTypeSelect` | `https:///admin/config/actions.checkoutAccountTypeSelect` | | `actions.checkoutBillAddressSelect` | `https:///admin/config/actions.checkoutBillAddressSelect` | | `actions.checkoutCommitDraftAddress` | `https:///admin/config/actions.checkoutCommitDraftAddress` | | `actions.checkoutConfirm` | `https:///admin/config/actions.checkoutConfirm` | | `actions.checkoutPaymentUpdate` | `https:///admin/config/actions.checkoutPaymentUpdate` | | `actions.checkoutPseudoCCSelect` | `https:///admin/config/actions.checkoutPseudoCCSelect` | | `actions.checkoutSetCustomerData` | `https:///admin/config/actions.checkoutSetCustomerData` | | `actions.checkoutSetDraftAddress` | `https:///admin/config/actions.checkoutSetDraftAddress` | | `actions.checkoutSetFreeFields` | `https:///admin/config/actions.checkoutSetFreeFields` | | `actions.checkoutSetGuestEmail` | `https:///admin/config/actions.checkoutSetGuestEmail` | | `actions.checkoutSetVerificationStatus` | `https:///admin/config/actions.checkoutSetVerificationStatus` | | `actions.checkoutShippingAddressSelect` | `https:///admin/config/actions.checkoutShippingAddressSelect` | | `actions.checkoutShippingMethodUpdate` | `https:///admin/config/actions.checkoutShippingMethodUpdate` | | `actions.checkoutStoreIdSelect` | `https:///admin/config/actions.checkoutStoreIdSelect` | | `actions.checkoutUseDifferentShippingAddress` | `https:///admin/config/actions.checkoutUseDifferentShippingAddress` | | `actions.checkPasswortStrength` | `https:///admin/config/actions.checkPasswortStrength` | | `actions.confirmZipCode` | `https:///admin/config/actions.confirmZipCode` | | `actions.consentChange` | `https:///admin/config/actions.consentChange` | | `actions.creditCardDelete` | `https:///admin/config/actions.creditCardDelete` | | `actions.directOrder` | `https:///admin/config/actions.directOrder` | | `actions.emailUpdate` | `https:///admin/config/actions.emailUpdate` | | `actions.emailVerify` | `https:///admin/config/actions.emailVerify` | | `actions.guestRegister` | `https:///admin/config/actions.guestRegister` | | `actions.inquirySend` | `https:///admin/config/actions.inquirySend` | | `actions.inventoryReserve` | `https:///admin/config/actions.inventoryReserve` | | `actions.loadMembersBasket` | `https:///admin/config/actions.loadMembersBasket` | | `actions.login` | `https:///admin/config/actions.login` | | `actions.newsletterSubscribe` | `https:///admin/config/actions.newsletterSubscribe` | | `actions.newsletterUnsubscribe` | `https:///admin/config/actions.newsletterUnsubscribe` | | `actions.passwordForgotten` | `https:///admin/config/actions.passwordForgotten` | | `actions.productRatingAdd` | `https:///admin/config/actions.productRatingAdd` | | `actions.productRatingDelete` | `https:///admin/config/actions.productRatingDelete` | | `actions.productRatingUpdate` | `https:///admin/config/actions.productRatingUpdate` | | `actions.refreshBasketSession` | `https:///admin/config/actions.refreshBasketSession` | | `actions.rejectBasket` | `https:///admin/config/actions.rejectBasket` | | `actions.removeDefaultBillAddress` | `https:///admin/config/actions.removeDefaultBillAddress` | | `actions.removeDefaultDeliveryAddress` | `https:///admin/config/actions.removeDefaultDeliveryAddress` | | `actions.resetBasket` | `https:///admin/config/actions.resetBasket` | | `actions.resetPassword` | `https:///admin/config/actions.resetPassword` | | `actions.saveMembersBasket` | `https:///admin/config/actions.saveMembersBasket` | | `actions.selectStore` | `https:///admin/config/actions.selectStore` | | `actions.sessionUnlock` | `https:///admin/config/actions.sessionUnlock` | | `actions.sessionUpdate` | `https:///admin/config/actions.sessionUpdate` | | `actions.setCustomerData` | `https:///admin/config/actions.setCustomerData` | | `actions.setDefaultBillAddress` | `https:///admin/config/actions.setDefaultBillAddress` | | `actions.setDefaultDeliveryAddress` | `https:///admin/config/actions.setDefaultDeliveryAddress` | | `actions.setMainAddress` | `https:///admin/config/actions.setMainAddress` | | `actions.subAccountCreate` | `https:///admin/config/actions.subAccountCreate` | | `actions.submitCustomerData` | `https:///admin/config/actions.submitCustomerData` | | `actions.testModeChange` | `https:///admin/config/actions.testModeChange` | | `actions.testModeOff` | `https:///admin/config/actions.testModeOff` | | `actions.testModeOn` | `https:///admin/config/actions.testModeOn` | | `actions.triggerMemberPasswordReset` | `https:///admin/config/actions.triggerMemberPasswordReset` | | `actions.unlockLogin` | `https:///admin/config/actions.unlockLogin` | | `actions.updateApplePay` | `https:///admin/config/actions.updateApplePay` | | `actions.updateGooglePay` | `https:///admin/config/actions.updateGooglePay` | | `actions.updatePrivileges` | `https:///admin/config/actions.updatePrivileges` | | `actions.verifyBasket` | `https:///admin/config/actions.verifyBasket` | | `actions.voucherAdd` | `https:///admin/config/actions.voucherAdd` | | `actions.voucherDelete` | `https:///admin/config/actions.voucherDelete` | | `actions.watchListAdd` | `https:///admin/config/actions.watchListAdd` | | `actions.watchListDelete` | `https:///admin/config/actions.watchListDelete` | | `actions.watchListItemAdd` | `https:///admin/config/actions.watchListItemAdd` | | `actions.watchListItemDelete` | `https:///admin/config/actions.watchListItemDelete` | ### app – WEBSALE APP WEBSALE APP:
Aktivierungsstatus, Authentifizierung, Push-Benachrichtigungen und Service-Accounts. Details: [app-Konfiguration](/konfiguration/app-websale-app). | Konfigurationsknoten | Deeplink | | -------------------------- | ------------------------------------------------------------- | | `app.app` | `https:///admin/config/app.app` | | `app.googleServiceAccount` | `https:///admin/config/app.googleServiceAccount` | | `app.instances` | `https:///admin/config/app.instances` | ### authentication – Authentifizierungs- & Zugriffsdaten Zugangsdaten externer Authentifizierungsprovider wie Google OAuth 2.0 und Firebase Cloud Messaging.
Details: [authentication-Konfiguration](/konfiguration/authentication-authentifizierungs-zugriffsdaten). | Konfigurationsknoten | Deeplink | | ------------------------------- | ------------------------------------------------------------------ | | `authentication.googleOAuthKey` | `https:///admin/config/authentication.googleOAuthKey` | ### b2b – Business-to-Business B2B:
Kundengruppen, Berechtigungen und Preislogik für Geschäftskunden.
Details: [b2b-Konfiguration](/konfiguration/b2b-business-to-business-b2b). | Konfigurationsknoten | Deeplink | | ------------------------- | ------------------------------------------------------------ | | `b2b.access` | `https:///admin/config/b2b.access` | | `b2b.accountVerification` | `https:///admin/config/b2b.accountVerification` | | `b2b.subAccounts` | `https:///admin/config/b2b.subAccounts` | | `b2b.userInvitation` | `https:///admin/config/b2b.userInvitation` | ### basket – Warenkorb Warenkorbverhalten, automatische Beigaben (autobasket), Warenkorb-Cookies und Speicherdauer.
Details: [basket-Konfiguration](/konfiguration/basket-warenkorb). | Konfigurationsknoten | Deeplink | | -------------------- | ------------------------------------------------------ | | `basket.autobasket` | `https:///admin/config/basket.autobasket` | | `basket.basket` | `https:///admin/config/basket.basket` | ### checkout – Bestellablauf Bestellablauf:
Versand- und Zahlungsarten, Voucher, Sendungsverfolgung und Direktbestellung.
Details: [checkout-Konfiguration](/konfiguration/checkout-bestellablauf). | Konfigurationsknoten | Deeplink | | ------------------------------ | ----------------------------------------------------------------- | | `checkout.checkout` | `https:///admin/config/checkout.checkout` | | `checkout.directOrder` | `https:///admin/config/checkout.directOrder` | | `checkout.productDependency` | `https:///admin/config/checkout.productDependency` | | `checkout.shippingMethod` | `https:///admin/config/checkout.shippingMethod` | | `checkout.shippingMethodGroup` | `https:///admin/config/checkout.shippingMethodGroup` | | `checkout.shipTrack` | `https:///admin/config/checkout.shipTrack` | | `checkout.voucher` | `https:///admin/config/checkout.voucher` | | `checkout.voucherErrors` | `https:///admin/config/checkout.voucherErrors` | ### content – Katalog (Kategorien & Produkte) Katalogstrukturen:
Kategorien, Produktfelder, Varianten, Produkttypen sowie Bild- und Medienverwaltung.
Details: [content-Konfiguration](/konfiguration/content-katalog-kategorien-produkte). | Konfigurationsknoten | Deeplink | | ------------------------------- | ------------------------------------------------------------------ | | `content.categoryField` | `https:///admin/config/content.categoryField` | | `content.categoryFieldGroup` | `https:///admin/config/content.categoryFieldGroup` | | `content.contentFieldDataTypes` | `https:///admin/config/content.contentFieldDataTypes` | | `content.customCategoryField` | `https:///admin/config/content.customCategoryField` | | `content.customProductField` | `https:///admin/config/content.customProductField` | | `content.imageFormat` | `https:///admin/config/content.imageFormat` | | `content.inventory` | `https:///admin/config/content.inventory` | | `content.productAttribute` | `https:///admin/config/content.productAttribute` | | `content.productField` | `https:///admin/config/content.productField` | | `content.productFieldGroup` | `https:///admin/config/content.productFieldGroup` | | `content.productSettings` | `https:///admin/config/content.productSettings` | | `content.productType` | `https:///admin/config/content.productType` | | `content.usedFields` | `https:///admin/config/content.usedFields` | | `content.videoSettings` | `https:///admin/config/content.videoSettings` | ### customer – Kundendaten Erfassung von Kundendaten:
Adressfelder, Pflichtangaben, Feldgruppen und Validierung.
Details: [customer-Konfiguration](/konfiguration/customer-kundendaten). | Konfigurationsknoten | Deeplink | | ------------------------------------- | ------------------------------------------------------------------------ | | `customer.customerDataField` | `https:///admin/config/customer.customerDataField` | | `customer.customerDataFieldsSettings` | `https:///admin/config/customer.customerDataFieldsSettings` | | `customer.customerDataGroup` | `https:///admin/config/customer.customerDataGroup` | ### finance – Währungen & Steuern Währungen, Preisformatierung, Brutto-/Netto-Logik, Steuersätze sowie Zuschläge.
Details: [finance-Konfiguration](/konfiguration/finance-wahrungen-steuern). | Konfigurationsknoten | Deeplink | | -------------------------- | ------------------------------------------------------------- | | `finance.conversionRates` | `https:///admin/config/finance.conversionRates` | | `finance.currency` | `https:///admin/config/finance.currency` | | `finance.exchangeRates` | `https:///admin/config/finance.exchangeRates` | | `finance.shopRent` | `https:///admin/config/finance.shopRent` | | `finance.shopRentTier` | `https:///admin/config/finance.shopRentTier` | | `finance.taxes` | `https:///admin/config/finance.taxes` | | `finance.taxRates` | `https:///admin/config/finance.taxRates` | | `finance.taxRatesAddition` | `https:///admin/config/finance.taxRatesAddition` | ### general – Allgemeine Shopeinstellungen Allgemeine Einstellungen:
Sprachen, Länder, Subshops, Kundenkonto, Sicherheit, Testmodus und Consent.
Details: [general-Konfiguration](/konfiguration/general-allgemeine-shopeinstellungen). | Konfigurationsknoten | Deeplink | | --------------------------------- | -------------------------------------------------------------------- | | `general.addressListElements` | `https:///admin/config/general.addressListElements` | | `general.adminAccountSettings` | `https:///admin/config/general.adminAccountSettings` | | `general.asse` | `https:///admin/config/general.asse` | | `general.asseRateLimit` | `https:///admin/config/general.asseRateLimit` | | `general.consentCookieGroup` | `https:///admin/config/general.consentCookieGroup` | | `general.consentCookieService` | `https:///admin/config/general.consentCookieService` | | `general.country` | `https:///admin/config/general.country` | | `general.customerAccountSettings` | `https:///admin/config/general.customerAccountSettings` | | `general.deviceTypes` | `https:///admin/config/general.deviceTypes` | | `general.garbageCollection` | `https:///admin/config/general.garbageCollection` | | `general.general` | `https:///admin/config/general.general` | | `general.imageConverter` | `https:///admin/config/general.imageConverter` | | `general.language` | `https:///admin/config/general.language` | | `general.numberFormat` | `https:///admin/config/general.numberFormat` | | `general.order` | `https:///admin/config/general.order` | | `general.orderSortOption` | `https:///admin/config/general.orderSortOption` | | `general.productRating` | `https:///admin/config/general.productRating` | | `general.salutation` | `https:///admin/config/general.salutation` | | `general.sitemap` | `https:///admin/config/general.sitemap` | | `general.subshop` | `https:///admin/config/general.subshop` | | `general.subshopView` | `https:///admin/config/general.subshopView` | | `general.testMode` | `https:///admin/config/general.testMode` | | `general.title` | `https:///admin/config/general.title` | | `general.zipCodes` | `https:///admin/config/general.zipCodes` | ### inquiry – Formulare Shopseitige Formulare:
Kontakt-, Widerrufs-, Retouren- und Katalogbestellformulare.
Der Knoten `inquiry.form` wird in der Konfigurationsübersicht nicht angeboten, die Formulare werden über den Service *Anfragen* gepflegt.
Details: [inquiry-Konfiguration](/konfiguration/inquiry-formulare). | Konfigurationsknoten | Deeplink | | --------------------- | -------------------------------------------------------- | | `inquiry.fieldPreset` | `https:///admin/config/inquiry.fieldPreset` | | `inquiry.form` | `https:///admin/config/inquiry.form` | | `inquiry.ruleSet` | `https:///admin/config/inquiry.ruleSet` | ### maintenance – Wartungsmodus Wartungsmodus:
Shop temporär sperren und individuelle Wartungsmeldung anzeigen.
Details: [maintenance-Konfiguration](/konfiguration/maintenance-wartungsmodus). | Konfigurationsknoten | Deeplink | | ------------------------- | ------------------------------------------------------------ | | `maintenance.maintenance` | `https:///admin/config/maintenance.maintenance` | ### messages – Ereignisgesteuerte E-Mails Ereignisgesteuerte, benutzerdefinierte E-Mails an Verantwortliche, Lieferanten oder Hersteller. Details: [messages-Konfiguration](/konfiguration/messages-ereignisgesteuerte-e-mails). | Konfigurationsknoten | Deeplink | | -------------------- | ---------------------------------------------------- | | `messages.emails` | `https:///admin/config/messages.emails` | ### newsletter – Newsletter An- und Abmeldung, Double-Opt-In-Bestätigungen sowie zugehörige E-Mail-Formulare. Details: [newsletter-Konfiguration](/konfiguration/newsletter-newsletter). | Konfigurationsknoten | Deeplink | | ----------------------- | ---------------------------------------------------------- | | `newsletter.field` | `https:///admin/config/newsletter.field` | | `newsletter.newsletter` | `https:///admin/config/newsletter.newsletter` | ### payment – Zahlungsmethoden Zahlungskonfiguration: einzelne Zahlungsarten, Anzeigeregeln und Payment-Provider.
Details: [payment-Konfiguration](/konfiguration/payment-zahlungsmethoden). | Konfigurationsknoten | Deeplink | | ------------------------------ | ----------------------------------------------------------------- | | `payment.computopHosted` | `https:///admin/config/payment.computopHosted` | | `payment.payment` | `https:///admin/config/payment.payment` | | `payment.paymentBlock` | `https:///admin/config/payment.paymentBlock` | | `payment.payPalCheckout` | `https:///admin/config/payment.payPalCheckout` | | `payment.stripe` | `https:///admin/config/payment.stripe` | | `payment.transactionsSettings` | `https:///admin/config/payment.transactionsSettings` | ### search – Sortierung und Filterung Interne Produktsuche und Listing:
Filter, Sortieroptionen und wiederverwendbare Regeln.
Details: [search-Konfiguration](/konfiguration/search-sortierung-und-filterung). | Konfigurationsknoten | Deeplink | | -------------------------------- | ------------------------------------------------------------------- | | `search.categoryNavigation` | `https:///admin/config/search.categoryNavigation` | | `search.productFilter` | `https:///admin/config/search.productFilter` | | `search.productSearchNavigation` | `https:///admin/config/search.productSearchNavigation` | | `search.productSortOption` | `https:///admin/config/search.productSortOption` | ### security – Sicherheitsregeln Sicherheitsrelevante Einstellungen:
Bot-Schutz, Hash- und Verschlüsselungsmethoden, Schlüssel.
Details: [security-Konfiguration](/konfiguration/security-sicherheitsregeln). | Konfigurationsknoten | Deeplink | | ---------------------------- | --------------------------------------------------------------- | | `security.actionGuard` | `https:///admin/config/security.actionGuard` | | `security.friendlyCaptchaV1` | `https:///admin/config/security.friendlyCaptchaV1` | | `security.method` | `https:///admin/config/security.method` | | `security.recaptchav3` | `https:///admin/config/security.recaptchav3` | ### seoMetaData – Meta-Daten & SEO-Texte Aufbau von Meta-Title und Meta-Description für Kategorien, Produkte, Startseite und Templates.
Details: [seoMetaData-Konfiguration](/konfiguration/seometadata-meta-daten-seo-texte). | Konfigurationsknoten | Deeplink | | ----------------------------- | ---------------------------------------------------------------- | | `seoMetaData.categorySchemes` | `https:///admin/config/seoMetaData.categorySchemes` | | `seoMetaData.generalSchemes` | `https:///admin/config/seoMetaData.generalSchemes` | | `seoMetaData.productSchemes` | `https:///admin/config/seoMetaData.productSchemes` | | `seoMetaData.startPage` | `https:///admin/config/seoMetaData.startPage` | | `seoMetaData.viewSchemes` | `https:///admin/config/seoMetaData.viewSchemes` | ### shopSystemServices – Shop-Dienste Ergänzende Shop-Dienste (z. B. „Zusammen gekauft“). | Konfigurationsknoten | Deeplink | | ----------------------------------- | ---------------------------------------------------------------------- | | `shopSystemServices.boughtTogether` | `https:///admin/config/shopSystemServices.boughtTogether` | ### statistics – Statistikdaten Statistik-Konfiguration:
Tracking-Anbieter, Conversion-Events und Datenbereitstellung.
Details: [statistics-Konfiguration](/konfiguration/statistics-statistikdaten). | Konfigurationsknoten | Deeplink | | -------------------------- | ------------------------------------------------------------- | | `statistics.dataRetention` | `https:///admin/config/statistics.dataRetention` | ### storefrontApi – Storefront-API Konfiguration der Storefront-API für die Anbindung externer Frontends.
Details: [storefrontApi-Konfiguration](/konfiguration/storefrontapi-storefront-api). | Konfigurationsknoten | Deeplink | | ---------------------------------- | --------------------------------------------------------------------- | | `storefrontApi.catalogApiSettings` | `https:///admin/config/storefrontApi.catalogApiSettings` | | `storefrontApi.redirects` | `https:///admin/config/storefrontApi.redirects` | ### system – Grundlegende Systemkonfiguration Grundlegende, infrastrukturelle Konfigurationen des technischen Systemverhaltens.
Details: [system-Konfiguration](/konfiguration/system). | Konfigurationsknoten | Deeplink | | ----------------------- | ---------------------------------------------------------- | | `system.trustedProxies` | `https:///admin/config/system.trustedProxies` | ### urls – URL (Webadressen) URL-Konfiguration:
hreflang-Alternativen, Weiterleitungen und Aufbau der SEO-URLs.
Details: [urls-Konfiguration](/konfiguration/urls-url-webadressen). | Konfigurationsknoten | Deeplink | | -------------------- | --------------------------------------------------- | | `urls.hreflang` | `https:///admin/config/urls.hreflang` | | `urls.redirects` | `https:///admin/config/urls.redirects` | | `urls.urls` | `https:///admin/config/urls.urls` | *** # Frontend - Übersicht Source: https://dokumentation.websale.de/frontend Templatebasierte Umsetzung des Shop-Frontends in WEBSALE: Template Engine, Sprachreferenz, Shop-Templates und Aufbau eigener Themes über HTML, CSS und JS. Der Aufbau eines Shop-Frontends ist in WEBSALE grundsätzlich kein Baukastensystem: Es gibt keine Drag-&-Drop-Oberfläche, und WEBSALE stellt kein Theme- oder Baukastensystem bereit. Für Anpassungen werden Kenntnisse in HTML, CSS und JavaScript benötigt; bei einem Headless-Frontend auf Basis der Storefront API zusätzlich entsprechende Framework-Kenntnisse. Der Bereich **Frontend** beschreibt die templatebasierte Umsetzung des Shop-Frontends innerhalb der WEBSALE Shopplattform. Im Fokus stehen die Template Engine / Template-Sprache sowie die Shop-Templates und deren Struktur – also alles, was für den Aufbau und die Anpassung der Darstellung über Templates erforderlich ist. Die Umsetzung eines Frontends über die [Storefront API](/schnittstellen/storefront-api) (z. B. für Headless-Projekte mit React, Vue, Next.js oder Nuxt) ist nicht Bestandteil dieses Kapitels. Diese Inhalte sind im Bereich [Schnittstellen](/schnittstellen) → [Storefront API](/schnittstellen/storefront-api) dokumentiert. Bei der Bereitstellung eines Shops ist im Standard der templatebasierte [WEBSALE Demoshop](https://demo.shop.websale.biz/) bereits enthalten, der als Ausgangsbasis für Anpassungen genutzt werden kann. Details zum Demoshop finden Sie hier. ## Inhalte templatebasiertes Frontend * [Die Basics](/frontend/die-basics) — Der Bereich Basics bietet einen Überblick über die zentralen Konzepte zur Anpassung und Individualisierung eines WEBSALE-Onlineshops. Hier finden Sie die wesentlichen Voraussetzungen für die Bearbeitung eines Shops und erfahren, welche technischen Möglichkeiten WEBSALE dafür bereitstellt. * [Getting Started](/frontend/getting-started) — Ein WEBSALE-Onlineshop bietet zahlreiche Möglichkeiten zur individuellen Anpassung und Konfiguration. Damit Sie schnell und effizient starten können, führt diese Anleitung Sie Schritt für Schritt durch die wichtigsten ersten Aufgaben. * [Datenzugriff & Anzeige](/frontend/datenzugriff-anzeige) — Im Rahmen der neuen Shopversion bietet das System flexible Möglichkeiten, um auf verschiedene Datenquellen des Shops zuzugreifen und diese gezielt im Frontend darzustellen. Für die Umsetzung spezifischer Seiten oder Funktionen ist es notwendig, die richtigen Variablen und Tags zu kennen, um beispielsweise Produktdetails, Kategorien, Zahlungsarten oder Adressdaten dynamisch einzubinden. * [Funktionsübersicht](/frontend/funktionsubersicht/bestellablauf) * [Referenz](/frontend/referenz) — Referenz ist das zentrale Nachschlagewerk für die Template Engine und die Template-Sprache. Hier sind alle relevanten Sprachelemente und Bausteine dokumentiert, die für den Aufbau und die Anpassung des Shop-Frontends auf Basis von Templates benötigt werden – zum Beispiel Tags/Anweisungen, Variablen, Funktionen, Modifier und typische Verwendungsformen. * [Praxisbeispiele](/frontend/praxisbeispiele) # Übersicht - Die Basics Source: https://dokumentation.websale.de/frontend/die-basics Einstieg in die WEBSALE-Grundlagen: Best Practice Shop, Template Theme, Template Engine und Konfiguration per Code für individuelle Shopanpassungen. Der Bereich **Basics** bietet einen Überblick über die zentralen Konzepte zur Anpassung und Individualisierung eines WEBSALE-Onlineshops. Hier finden Sie die wesentlichen Voraussetzungen für die Bearbeitung eines Shops und erfahren, welche technischen Möglichkeiten WEBSALE dafür bereitstellt. Die einzelnen Seiten in diesem Bereich behandeln Themen wie den Best Practice Shop als Ausgangspunkt für individuelle Anpassungen, die Template-Struktur, die WEBSALE Template-Sprache sowie die Möglichkeit, Konfigurationen direkt per Code vorzunehmen. Dieser Bereich richtet sich an Entwickler und Webdesigner, die sich mit der technischen Struktur von WEBSALE vertraut machen und den Shop gezielt anpassen möchten. ## Überblick * [Alles für den Start](/frontend/die-basics/alles-fur-den-start) — Bevor ein WEBSALE-Onlineshop individuell angepasst werden kann, sind einige grundlegende Voraussetzungen erforderlich. Auf dieser Seite wird erläutert, welche technischen und administrativen Zugänge notwendig sind, um mit der Bearbeitung zu beginnen. * [BestPractice Shop](/frontend/die-basics/bestpractice-shop) — Der WEBSALE Best Practice Shop, auch als Auslieferungsshop bezeichnet, wird beim Kauf eines WEBSALE Onlineshops bereitgestellt und dient als Ausgangspunkt für die individuelle Gestaltung des zukünftigen Shops. Er enthält ein Start-Design sowie eine grundlegende Konfiguration, die speziell auf die Anforderungen eines deutschen B2C-Shops zugeschnitten ist. * [Template Theme](/frontend/die-basics/template-theme) — Die Gestaltung der Storefront bei WEBSALE ist flexibel und ermöglicht individuelle Anpassungen, erfordert jedoch fortgeschrittenes Know-how in HTML, CSS und JavaScript. Anders als bei anderen Shopsystemen gibt es bei WEBSALE keine vorgefertigten Designs oder Drag-and-Drop-Builder. Stattdessen arbeiten Webdesigner und Frontend-Entwickler direkt mit den HTML-Templates, CSS- und JavaScript-Dateien, um das gewünschte Design zu realisieren. * [Template Engine](/frontend/die-basics/template-engine) — Die WEBSALE Template-Sprache bietet eine leistungsstarke und flexible Möglichkeit, das Frontend eines Onlineshops individuell zu gestalten. Dynamische Inhalte wie Produkt- oder Benutzerdaten können nahtlos in HTML-Templates eingebunden und sprachabhängige Texte oder komplexe Bedingungen berücksichtigt werden. * [Konfiguration per Code](/frontend/die-basics/konfiguration-per-code) — Neben den Eingabemasken und Schaltflächen im Admin Interface, mit denen sich ein WEBSALE-Onlineshop über eine grafische Oberfläche konfigurieren lässt, besteht die Möglichkeit, diese Einstellungen durch eine Konfiguration per Code gezielt zu überschreiben oder zu erweitern. * [Wissenswertes](/frontend/die-basics/wissenswertes) # Alles für den Start Source: https://dokumentation.websale.de/frontend/die-basics/alles-fur-den-start Voraussetzungen für die Bearbeitung eines WEBSALE-Shops: notwendige Zugänge zu Admin Interface, GitLab-Repository und Werkzeuge für Frontend-Entwickler. Bevor ein WEBSALE-Onlineshop individuell angepasst werden kann, sind einige grundlegende Voraussetzungen erforderlich. Auf dieser Seite wird erläutert, welche technischen und administrativen Zugänge notwendig sind, um mit der Bearbeitung zu beginnen. *** ## Ein bereitgestellter WEBSALE-Onlineshop Ein [**bereitgestellter WEBSALE-Onlineshop**](https://demo.shop.websale.biz/) bildet die Basis für alle Anpassungen. Er enthält vorbereitete Konfigurationen, Standard-Templates für die Storefront und Tools zur Verwaltung von Shop-Daten und Einstellungen. Der Shop sowie die initialen Zugangsdaten zum Admin-Interface (Erst-Benutzer) und zu GitLab werden von WEBSALE bei der Bereitstellung zur Verfügung gestellt. ## Zugang zum Admin Interface des Shops Darüber hinaus ist der Zugang zum [**Admin Interface**](/admin-interface) erforderlich, um wichtige Konfigurationen wie Steuern, Währungen, Sprachen, Produkte sowie Versand- und Zahlungsarten anzupassen. Die entsprechenden Berechtigungen sind Voraussetzung für die Bearbeitung. ## Zugang zu GitLab Für die Entwicklung und Verwaltung der Storefront-Dateien wird standardmäßig [**GitLab**](https://about.gitlab.com/) genutzt. Es ermöglicht die Versionsverwaltung und das strukturierte Arbeiten mit den Template-Dateien. Änderungen am Code können nachvollzogen, dokumentiert und zwischen Entwicklern geteilt werden. ## Ein geeignetes Code-Editor-Programm Zusätzlich wird ein geeigneter Code-Editor benötigt, um HTML-, CSS- und JavaScript-Dateien effizient zu bearbeiten. Programme wie [**Visual Studio Code**](https://code.visualstudio.com/) oder [**Sublime Text**](https://www.sublimetext.com/) bieten praktische Funktionen wie Syntax-Highlighting und Auto-Vervollständigung, um die Arbeit zu erleichtern. Der Code-Editor muss selbst organisiert werden und ist nicht Bestandteil der WEBSALE-Bereitstellung. ## Zugang zu strapi CMS (optional) Der [WEBSALE Demoshop](https://demo.shop.websale.biz/ "https://demo.shop.websale.biz/") wird standardmäßig mit dem CMS Strapi ausgeliefert und enthält bereits einen definierten Satz an Eingabemasken und passenden Darstellungen für Ihre zukünftigen Shop-Inhalte. Bei der Bereitstellung Ihres Shops können Sie jedoch entscheiden, ob eine Strapi-Instanz eingerichtet werden soll – möchten Sie ein anderes CMS verwenden, entfällt die Einrichtung von Strapi. ## **Zugriff auf den Objektspeicher (S3)** Über diesen Zugang erhalten Sie Zugriff auf alle Dateien des Shops, z.B. Produktbilder, [JSON-Dateien](/schnittstellen/externe-datenschnittstelle-datei-bucket-basiert "https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3748724781") etc. Für den Zugriff auf den S3-Objektspeicher können Sie zusätzlich zu Ihrem Browser einen S3-kompatiblen Client, z. B. Minio Client, Cyberduck, S3 Browser (Windows) oder das AWS CLI verwenden. *** # BestPractice Shop Source: https://dokumentation.websale.de/frontend/die-basics/bestpractice-shop Best Practice Shop von WEBSALE als Ausgangspunkt: vorkonfiguriertes Design und Grundeinstellungen für deutsche B2C-Shops als Auslieferungsbasis nutzen. Der WEBSALE Best Practice Shop, auch als Auslieferungsshop bezeichnet, wird beim Kauf eines WEBSALE Onlineshops bereitgestellt und dient als Ausgangspunkt für die individuelle Gestaltung des zukünftigen Shops. Er enthält ein Start-Design sowie eine grundlegende Konfiguration, die speziell auf die Anforderungen eines deutschen B2C-Shops zugeschnitten ist. *** ## Grundkonfiguration Der Auslieferungsshop ist so vorkonfiguriert, dass er direkt einsatzbereit ist. Die enthaltenen Einstellungen umfassen: * **Währung:** Standardwährung ist Euro (€). * **Steuersätze:** Enthält die deutschen Mehrwertsteuersätze von 19 % und 7 %. * **Sprache:** Standardmäßig auf Deutsch eingestellt. * **Versandarten:** Vorkonfigurierte Versandoptionen, die angepasst werden können. * **Zahlungsarten:** Basis-Integration für Standard-Zahlungsmethoden wie Überweisung oder PayPal. ## Shop-Funktionen Die BestPractice Storefront bietet eine Vielzahl von Funktionen, die speziell für den Einsatz im E-Commerce optimiert wurden. Diese Funktionen verbessern das Einkaufserlebnis und bieten umfassende Werkzeuge für die Shop-Verwaltung: * **AutoLogin:** Ermöglicht registrierten Kunden, sich automatisch anzumelden. * **Merkzettel:** Produkte können gespeichert und später angesehen werden. * **Produktsuche mit Suggest:** Intelligente Suchvorschläge bei der Eingabe. * **Filter- und Sortieroptionen:** Verfeinerung der Ergebnisse in Kategorien und Suchlisten. * **Kundenkonto:** Bietet Funktionen für Bestellübersicht, Adressverwaltung und mehr. * **Produktbewertungen:** Kunden können Bewertungen abgeben und ansehen etc. ## Weitere Funktionen und Benutzerfreundlichkeit Neben den spezifischen Shop-Funktionen bietet der BestPractice Shop zusätzliche Eigenschaften, die für ein optimales Nutzungserlebnis und eine moderne Gestaltung sorgen: * **Responsive Design:** Optimiert für Smartphones, Tablets, Notebooks und Desktop-PCs. * **Barrierefreiheit:** Zugänglich für alle Nutzer, unabhängig von Einschränkungen. * **SEO-Basis-Optimierung:** Saubere URLs, Lazy Loading für schnelles Nachladen von Inhalten und weitere grundlegende SEO-Maßnahmen für bessere Sichtbarkeit. * **DSGVO-Konformität:** Datenschutzkonformität durch integrierte Lösungen wie Cookie-Banner und konfigurierbare Datenschutzeinstellungen. ## Verwendete Technologien Der Best Practice Shop basiert auf modernen Technologien, um eine stabile und flexible Grundlage für die Entwicklung zu bieten: * **Bootstrap:** Für ein responsives und anpassbares Frontend-Framework. * **jQuery:** Zur Optimierung von Interaktionen und dynamischen Inhalten. * **HTML5 und CSS3:** Für eine moderne, semantische und barrierefreie Umsetzung. # Konfiguration per Code Source: https://dokumentation.websale.de/frontend/die-basics/konfiguration-per-code Shop-Einstellungen direkt per Code überschreiben und erweitern: Konfigurationsdateien anpassen, wenn das Admin Interface nicht ausreicht. Neben den Eingabemasken und Schaltflächen im Admin Interface, mit denen sich ein **WEBSALE**-Onlineshop über eine grafische Oberfläche konfigurieren lässt, besteht die Möglichkeit, diese Einstellungen durch eine Konfiguration per Code gezielt zu überschreiben oder zu erweitern. Diese Methode erlaubt es, Konfigurationen direkt in einem JSON-ähnlichen Format zu definieren. Dabei sind die Einstellungen in sogenannte Knoten unterteilt, für die – abhängig von der jeweiligen Konfiguration – spezifische Parameter und Werte zulässig sind. Ein Beispiel für die Konfiguration einer Währung könnte folgendermaßen aussehen: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "decimalPlaces": 2, "decimalSeparator": ",", "isoCode": "EUR", "isoNum": "978", "symbol": "€", "symbolPosition": "left", "thousandsSeparator": "." } ``` Diese Konfiguration definiert die Darstellung einer Währung im Shop, einschließlich der Anzahl der Dezimalstellen, der Trennzeichen für Tausender und Dezimalstellen sowie der Position des Währungssymbols. Die Konfiguration per Code folgt dem JSON-Format, sodass die JSON-Spezifikation für das Schreiben dieser Konfigurationsdateien gilt. Dies bedeutet, dass die Syntax strikt eingehalten werden muss, beispielsweise durch korrekte Klammerung und Zeichenketten in Anführungszeichen. Diese Methode ermöglicht es, komplexe oder individuelle Anpassungen vorzunehmen, die über die standardmäßigen Optionen im Admin Interface hinausgehen. Eine detaillierte Übersicht über die verfügbaren Parameter und Konfigurationsmöglichkeiten finden Sie in der Referenz unter [Konfiguration](/konfiguration). # Template Engine Source: https://dokumentation.websale.de/frontend/die-basics/template-engine WEBSALE Template-Engine erklärt: dynamische Inhalte einbinden, Bedingungen, Schleifen, mehrsprachige Texte und Escaping in HTML-Templates verarbeiten. Die WEBSALE Template-Sprache bietet eine leistungsstarke und flexible Möglichkeit, das Frontend eines Onlineshops individuell zu gestalten. Dynamische Inhalte wie Produkt- oder Benutzerdaten können nahtlos in HTML-Templates eingebunden und sprachabhängige Texte oder komplexe Bedingungen berücksichtigt werden. Diese Dokumentation vermittelt die grundlegenden Funktionen und Werkzeuge, die in der täglichen Arbeit bei der Gestaltung von Onlineshops häufig verwendet werden. Von der Verwendung von Variablen über die Anwendung von Schleifen und Bedingungen bis hin zur Nutzung von Modifikatoren wird beschrieben, wie Inhalte dynamisch gestaltet und angepasst werden können. *** ## WEBSALE Template Engine Die **WEBSALE Template Engine** wird für die komplette Erstellung und Gestaltung der Storefront verwendet. Sie benötigen keine Kenntnisse in Programmiersprachen wie PHP oder Java und auch kein Wissen über Datenbankzugriffe, um Ihren individuellen WEBSALE Onlineshop zu erstellen und anzupassen. Mit der WEBSALE Template Engine können dynamische Inhalte im Onlineshop einfach angezeigt werden – ganz ohne komplexe Backend-Logik. Als Template-Manager können Sie sich voll und ganz auf HTML, CSS und JavaScript konzentrieren und dynamische Daten wie Produktinformationen, Benutzerprofile oder Preise mithilfe unserer Template Engine und Template-Sprache einbinden. *** ## Grundlagen und Syntax der WEBSALE Template Engine In der WEBSALE-Template-Umgebung basieren alle Templates auf Standard-HTML-Dateien mit den Endungen `.htm` oder `.html`, die innerhalb der Shop-Verzeichnisstruktur abgelegt sind. Innerhalb dieser HTML-Dateien können sogenannte **Template-Tags** verwendet werden, um dynamische Inhalte oder sprachabhängige Texte in das Frontend einzubinden. Die Template-Tags ermöglichen die Einbindung von: * **Textbausteinen** für sprachabhängige Inhalte. * **Platzhaltern** für dynamische Inhalte wie Produktdaten, Benutzerdaten oder Shop-Funktionen. ### Textbausteine Textbausteine werden verwendet, um sprachabhängige Texte wie Button-Beschriftungen oder Überschriften zentral zu verwalten und in die Templates einzufügen. Ihre Syntax ist einfach und eindeutig: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} %%Textbausteinname%% ``` **Beispiel: Button “in den Warenkorb”** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` Textbausteine werden nicht nur in Templates verwendet, sondern auch in Konfigurationen, sofern dort sprachabhängige Texte für die Frontend-Ausgabe hinterlegt werden, zum Beispiel Anzeigetexte oder Beschreibungen. Weitere Informationen zur Verwendung von Textbausteinen in Konfigurationen finden Sie im Bereich [Konfigurationen](/konfiguration). ### Platzhalter (für dynamische Inhalte) Platzhalter dienen zur Einbindung von dynamischen Daten, die zur Laufzeit vom Backend bereitgestellt werden. Die Syntax ist HTML-ähnlich und verwendet doppelte geschweifte Klammern `{}`: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $variable }} ``` **Beispiel: Produktname und Produktbeschreibung** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}

{{= $myProduct.name}}

{{= $myProduct.description }}

``` Die Template Engine interpretiert diese Platzhalter und ersetzt sie zur Laufzeit mit den entsprechenden Werten aus dem System. ### Standard-Escaping Die WEBSALE Template-Engine verfügt über ein integriertes Standard-Escaping, das automatisch auf alle dynamisch eingebundenen Inhalte angewendet wird. Dadurch wird sichergestellt, dass HTML- oder JavaScript-Code, der z. B. in Produktdaten oder CMS-Inhalten enthalten ist, nicht interpretiert, sondern als Klartext dargestellt wird. Viele Inhalte im Shop – z. B. Produktbeschreibungen, CMS-Artikel oder andere redaktionelle Texte – enthalten HTML zur Formatierung. Damit diese Inhalte nicht unbeabsichtigt als echter HTML-Code ausgeführt werden, wird bei der Ausgabe mit `{{= ... }}` ein automatisches Escaping angewendet. **Beispiel: Standard-Escaping aktiviert** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $product.description }} ``` **Inhalt in den Shopdaten:** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}

Super atmungsaktiv – ideal für Sport und Freizeit. Jetzt in der neuesten Generation erhältlich.

``` **Ausgabe im Browser:** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} <p><strong>Super atmungsaktiv</strong> – ideal für Sport und Freizeit. Jetzt in der <em>neuesten Generation</em> erhältlich.</p> ``` Der HTML-Code wird **nicht interpretiert**, sondern als normaler Text angezeigt. Das schützt vor unbeabsichtigter Codeausführung. Wenn Inhalte bewusst als HTML ausgegeben werden sollen – z. B. weil Produkttexte oder CMS-Inhalte HTML enthalten und korrekt gerendert werden sollen – kann das Escaping gezielt deaktiviert werden. Dazu wird statt `=` ein Ausrufezeichen `!` verwendet: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{! $product.description }} ``` **Ausgabe im Browser:** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}

Super atmungsaktiv – ideal für Sport und Freizeit. Jetzt in der neuesten Generation erhältlich.

``` Jetzt wird der HTML-Code korrekt interpretiert und gerendert. **Wichtig:** Die Deaktivierung des Escapings sollte nur bei vertrauenswürdigen Inhalten erfolgen – z. B. bei Daten aus dem eigenen Produkt-Backend oder CMS. Inhalte, die z. B. über Formulareingaben von Kunden stammen, sollten nicht ungefiltert ohne Escaping ausgegeben werden. *** ## Variablen Mit der WEBSALE Template-Sprache können die Daten ausgegeben werden, die vom Shopsystem bereitgestellt werden. Jede Seite, die von der Template Engine gerendert wird, erhält so die benötigten Daten, um die angeforderten Inhalte anzuzeigen. Diese Daten werden in sogenannten Template-Variablen gespeichert. Alle Template-Variablen können über die Template-Sprache mit einem `$` gefolgt vom Variablennamen aufgerufen werden. Variablennamen können frei vergeben werden. Es gibt auch System-Variablen, die mit `$ws` beginnen und deren Namen vorgeben sind, z.B. `$wsProduct`, `$wsCategory` etc. Eine vollständige Übersicht der WEBSALE System-Variablen und mehr Informationen zu den Variablen allgemein finden Sie [hier](/frontend/referenz/variablen). ### Variablen setzen & verwenden **Beispiel: Neue Variable** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProduct = $wsProduct.load('1234') }} ``` Neue Variablen werden immer mit dem **var-Keyword** definiert. In diesem Beispiel lädt die Funktion `$wsProduct.load('1234')` die Produktdaten des Produkts mit der Artikelnummer `1234`. Diese werden in der Variable `$myProduct` gespeichert und können später verwendet werden. **Beispiel: Verwendung der Variablen** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProduct = $wsProduct.load('1234') }}

{{= $myProduct.name }}

{{= $myProduct.description }}

Preis: {{= $myProduct.price }} €

``` Einmal definierte Variablen können an beliebigen Stellen im Template genutzt werden. In diesem Fall: * Die Produktdaten werden in `$myProduct` gespeichert. * Der Produktname, die Beschreibung und der Preis werden dynamisch in das Template eingefügt. **Beispiel: Verschachtelte Variable** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProduct = $wsProduct.load('1234') }} Produktbild ``` Variablen können auch verschachtelt sein, um auf spezifische Werte innerhalb von komplexen Datenstrukturen wie Objekten oder Arrays zuzugreifen. Die Verschachtelung erfolgt immer durch Punkte `.` zwischen den einzelnen Ebenen. In diesem Beispiel: * `$product` ist die Hauptvariable für das Produkt. * `custom` verweist auf benutzerdefinierte Daten des Produkts. * `mainImage` gibt das Hauptbild des Produkts an. * `thumbnail` greift auf die verkleinerte Version des Bildes zu. Eine vollständige Liste aller Variablen sowie deren Beschreibung finden Sie in der [Übersicht der Variablen.](/frontend/referenz/variablen) ### Gültigkeitsbereich von Variablen Der Gültigkeitsbereich einer Variablen definiert, wo sie im Template verwendet werden kann. Variablen, die außerhalb von Bereichsanweisungen wie `if` oder `foreach` definiert werden, sind im gesamten Template gültig: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myCategory = $wsCategory.load('5678') }}

{{= $myCategory.name }}

{{ if $myCategory.isActive }}

Diese Kategorie ist aktiv.

{{ /if }} ``` Variablen, die innerhalb von Bereichsanweisungen definiert werden, existieren nur innerhalb dieses Bereichs: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $myProduct in $wsCategory.loadProducts('5678') }}

{{= $myProduct.name }}

{{= $myProduct.price }} €

{{ /foreach }}

{{= $myProduct.name }}

-> $myProduct ist außerhalb der Schleife nicht gültig ``` *** ## Modifiers (Modifikatoren) Manchmal reicht es nicht aus, den Inhalt einer Variable einfach nur auszugeben – der Wert muss vorher verändern oder angepasst werden. Genau dafür gibt es die **Modifiers**. **Modifiers** können auf alle Variablen angewendet werden, um deren Inhalt zu verändern. Dazu hängen sie einfach ein `|` (Pipe-Zeichen) und den Modifiernamen an die entsprechende Variable an. Zusätzliche Parameter werden mit `:` hinzugefügt. **Beispiel: Kürzen der Produktbeschreibung** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $myProduct.description|truncate:120 }} ``` In diesem Beispiel wird der Modifikator `truncate` auf die Produktbeschreibung angewendet. Dieser kürzt den Text auf eine maximale Länge von 120 Zeichen. **Beispiele: Mehrere Modifikatoren auf eine Variable anwenden** Sie können auch mehrere Modifikatoren hintereinander auf eine Variable anwenden. Diese werden in der Reihenfolge verarbeitet, in der sie angegeben werden. Eine vollständige Liste aller Modifiers sowie deren Beschreibung finden Sie in der [Übersicht der Modifikatoren.](/frontend/referenz/modifiers) *** ## Bedingungen (Conditions) Die WEBSALE `{if}`-Bedingungen erlauben die selbe Flexibilität wie in PHP oder Javascript, bis auf ein paar Erweiterungen für die Template-Engine. Jedes `{if}` muss mit einem `{/if}` kombiniert sein. `{else}` und `{elseif}` sind ebenfalls erlaubt. Alle gängigen PHP Vergleichsoperatoren und Funktionen, wie `||`, `or`, `&&`, `and`, `is_array()`, etc. sind erlaubt. Mit den WEBSALE `{if}`-Bedingungen können Sie die Ausgabe in der Storefront abhängig von bestimmten Bedingungen variieren. Um zu entscheiden, was ausgegeben wird, können Sie eine **Bedingung** definieren, die eine Variable überprüft. Eine einfache Bedingung wird durch einen `{if}-`Block dargestellt, der eine Prüfung enthält. Dieser Block wird nur dann ausgeführt, wenn die Prüfung wahr (true) ist. **Beispiel:** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $myProduct.description }} {{= $myPproduct.description }} {{ else }} {{= $myProduct.custom.shortdescr }} {{ /if }} ``` In diesem Beispiel prüfen wir, ob die Variable `$myProduct.description` Inhalt besitzt. Wenn ja, wird ihr Inhalt ausgegeben. Ist das nicht der Fall, wird der alternative Inhalt im **else**-Block gerendert. Hier verwenden die Kurzbeschreibung. Zusätzlich zu `if` und `else` können auch komplexere Bedingungen definiert, indem `{elseif}` hinzugefügt wird. Dadurch können mehrere Prüfungen in einer einzigen Bedingung kombiniert werden. **Beispiel: Begrüßung des Besuchers im Onlineshop** * Es wird eine persönliche Begrüßung angezeigt, wenn sich ein Bestandskunde eingeloggt. * Es wird eine andere Begrüßung angezeigt, wenn sich ein Neukunde eingeloggt. * Für alle nicht eingeloggte Besucher wird eine allgemeine Nachricht angezeigt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.isLoggedIn }}

Willkommen zurück, {{= $wsAccount.name }}!

{{ elseif $wsAccount.isLoggedIn.newUser }}

Willkommen in unserem Onlineshop, {{= $wsAccount.name }}

{{ else }}

Willkommen! Registrieren Sie sich.

{{ /if }} ``` **Beispiel: Komplexe Bedingungen mit Operatoren, z.B. für den Lagerbestand** Sie können unterschiedliche Operatoren verwenden, um komplexe Bedingungen zu erstellen, z. B.: * `>` oder `<` für Vergleiche der Stückzahl eines Produktes ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $myProduct.stock > 0 }}

Dieses Produkt ist verfügbar.

{{ else }}

Dieses Produkt nicht verfügbar.

{{ /if }} ``` Eine vollständige Übersicht der verfügbaren Operatoren und deren Verwendung finden Sie in der [Dokumentation der Bedingungen (Conditions)](/frontend/referenz/conditions). *** ## Loops (Schleifen) Schleifen ermöglichen es, durch ein Array zu iterieren, das mehrere Datensätze (z. B. Produkte) enthält, und automatisch Inhalte für jeden einzelnen Datensatz zu generieren. Damit können Sie wiederholende Strukturen wie Produktlisten, Bildergalerien oder ähnliche Inhalte effizient erstellen. Eine `foreach`-Schleife wird mit dem Tag `{{ foreach }}` geöffnet und mit `{{ /foreach }}` geschlossen. Der Name der Schleife (die sogenannte Laufvariable) kann frei definiert werden und darf Buchstaben, Zahlen sowie Unterstriche enthalten. Die `foreach`-Schleife durchläuft jedes Element des Arrays einmal und führt den eingeschlossenen Codeabschnitt für jedes Element aus. Mit jedem Durchlauf wird das aktuelle Element der Laufvariable zugewiesen. **Beispiel: Produktliste einer Kategorie** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ foreach $wsCategory.loadProducts('5678') as $myProduct }}

{{= $myProduct.name }}

{{= $myProduct.description }}

Preis: {{= $myProduct.price }} €

{{ foreachelse }}

Keine Produkte in dieser Kategorie verfügbar.

{{ /foreach }}
``` Die Schleife durchläuft alle Produkte einer Kategorie mit der ID `5678` und erstellt für jedes Produkt ein neues `
`-Element. Wenn keine Produkte in der Kategorie gefunden werden, wird der `foreachelse`-Bereich ausgeführt, und eine entsprechende Nachricht angezeigt. Vollständige Informationen zu den Schleifen finden Sie hier [hier.](/frontend/referenz/loops) *** ## Vollständige Referenzdokumentation Natürlich bietet die WEBSALE Template-Sprache noch viele weitere Funktionen und Möglichkeiten. Die oben beschriebenen Grundlagen gehören jedoch zu den am häufigsten genutzten Werkzeugen in der täglichen Arbeit bei der Bearbeitung des WEBSALE Onlineshops. Eine vollständige Übersicht aller Funktionen, Module, Aktionen und Möglichkeiten finden Sie in unserer [Referenzdokumentation](/frontend/referenz). # Template Theme Source: https://dokumentation.websale.de/frontend/die-basics/template-theme Aufbau des Template Themes verstehen: HTML-Templates, CSS- und JavaScript-Dateien für die Storefront direkt bearbeiten und individuell gestalten. Die Gestaltung der Storefront bei WEBSALE ist flexibel und ermöglicht individuelle Anpassungen, erfordert jedoch fortgeschrittenes Know-how in **HTML**, **CSS** und **JavaScript**. Anders als bei anderen Shopsystemen gibt es bei WEBSALE keine vorgefertigten Designs oder Drag-and-Drop-Builder. Stattdessen arbeiten Webdesigner und Frontend-Entwickler direkt mit den HTML-Templates, CSS- und JavaScript-Dateien, um das gewünschte Design zu realisieren. Ein wesentlicher Vorteil dieses Ansatzes ist, dass die Software von WEBSALE strikt vom Design resp. der Storefront getrennt ist. Änderungen oder Updates an der Software betreffen nicht die Templates. Die Storefront bleibt somit immer unverändert. Neue Funktionen aus Software-Updates können bei Bedarf manuell in die Templates integriert werden. *** ## Verzeichnisstruktur Die WEBSALE Storefront ist logisch in verschiedene Verzeichnisse unterteilt, die die Templates und zugehörigen Ressourcen wie CSS, JavaScript und Bilder strukturieren. ### Template-Verzeichnis Das Verzeichnis `templates/` enthält alle HTML-Templates der Storefront. Diese sind in Unterverzeichnisse organisiert, die nach den entsprechenden Controllern benannt sind. Diese Struktur trennt die Vorlagendateien nach den spezifischen Frontend-Bereichen, auf die sie sich beziehen. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} templates ├── components │ └── inline-scripts │ └── spc ├── layouts ├── mails │ └── comment ├── pdfs ├── views │ └── account │ └── checkout │ └── newsletter │ └── other ``` **Bedeutung der Unterverzeichnisse:** * `templates/components/`: Wiederverwendbare Template-Elemente (Includes), z.B. Produktboxen. * `templates/layouts/`: Basis-Templates (Layout-Templates), die das allgemeine Grundgerüst aller Shopseiten definieren (z.B. Header, Footer, Navigation). * `templates/mails/`: Templates für automatisch versendete E-Mails, z.B. Bestellbestätigungen oder Versandbenachrichtigungen. Das Verzeichnis `mails` ist fest vorgegeben und kann nicht umbenannt oder verschoben werden. E-Mail-Templates müssen direkt in diesem Verzeichnis liegen. In den E-Mail-Konfigurationen wird beim `template`-Parameter nur der Dateiname ohne das Präfix `mails/` angegeben (siehe [E-Mails & E-Mail Einstellungen](/konfiguration/e-mails-e-mail-einstellungen)). * `templates/pdfs/`: Templates für PDF-Ausgaben, z.B. Rechnungen oder Lieferscheine. * `templates/views/`: Seiten-Templates (View-Templates) für die einzelnen Shopseiten, z.B. Startseite, Kategorieseiten. Von diesen Unterverzeichnissen sind nur zwei fest vorgegeben, da das System sie direkt auswertet. Sie dürfen nicht umbenannt werden! * `templates/mails/` – enthält alle Mail-Templates. * `templates/views/` – enthält alle renderbaren Shop-Seiten (die einzigen von außen per Link adressierbaren Templates). Alle übrigen Verzeichnisse (z. B. `components/`, `layouts/`, `pdfs/`) sind eine empfohlene Organisationsstruktur und können frei benannt bzw. angelegt werden. ### Medien-Verzeichnis Das Verzeichnis `media/themes/default/` enthält die Ressourcen für die Gestaltung der Storefront, wie Schriftarten, SCSS-Dateien, Bilder und Icons. Dieses Verzeichnis befindet sich auf der gleichen Ebene wie `templates/`. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} media ├── themes │ └── default │ └── favicon │ └── fonts │ └── images │ └── scripts │ └── scss │ └── styles ``` Die Templates im Verzeichnis `templates/` greifen auf die Ressourcen im Verzeichnis `media/themes/default/` zu, um das Layout, die Farben, Schriftarten und Bilder der Storefront zu definieren. Dies ermöglicht eine saubere Trennung von Struktur (HTML) und Design (CSS und Medien). **Beispiel für die Einbindung von Ressourcen:** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` *** ## Basis-Template (Layout-Template) Das Basis-Template, auch als **Layout-Template** bezeichnet, legt das allgemeine Grundgerüst für alle Seiten der Storefront fest. Es definiert zentrale Inhalte und Bereiche, die auf den meisten Shopseiten wiederverwendet werden, und sorgt so für eine einheitliche Struktur und Benutzerführung. Das Layout-Template ist keine eigenständige Shopseite und kann nicht direkt von außen per Link aufgerufen werden. Es wird stattdessen von den spezifischen [Seiten-Templates (Views) ](#view-templates-seiten-templates)erweitert oder eingebunden. Das Basis-Template befindet sich im Verzeichnis ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} templates ├── layouts ``` Hier können ein oder mehrere Layout-Templates abgelegt werden, je nach Anwendungsfall (z. B. allgemeines Layout, Kundekonto, Checkout-spezifisches Layout, Mails etc.) Das Layout-Template enthält üblicherweise die folgenden zentralen Elemente: * **Technischer** ``**-Bereich:** * Meta-Angaben für Suchmaschinenoptimierung (z. B. Title, Description, Keywords). * Verweise auf die CSS- und JavaScript-Dateien der Storefront. * Integration von externen Ressourcen wie Schriftarten oder Tracking-Codes. * **Sichtbarer Headerbereich:** * Logo: Darstellung des Shop-Logos. * Suche: Eingabefeld für die Produktsuche. * Login-Bereich: Zugriff auf das Kundenkonto. * Warenkorb und Merkliste: Übersicht über gespeicherte Produkte. * Navigation: Primäre Navigation des Shops (z. B. Kategorien). * **Breadcrumb:** * Anzeige des aktuellen Navigationspfads zur besseren Orientierung der Benutzer. * **Footer:** * Weiterführende Verlinkungen wie Impressum, Datenschutz, AGB. * Kontaktinformationen oder andere zusätzliche Inhalte. Ein Layout-Template wird in den [Seiten-Templates (Views)](#view-templates-seiten-templates) über den `extends`**-Befehl** eingebunden: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ extends "layouts/default.htm" }} ``` *** ## Template-Blöcke Template-Blöcke bilden die grundlegende Struktur eines Basis-Templates und ermöglichen eine einfache und flexible Anpassung der Storefront. Sie gruppieren die Storefront-Komponenten in kleine, isolierte Blöcke, die unabhängig voneinander bearbeitet oder überschrieben werden können. Dieses Block-System sorgt für eine saubere Struktur und Wiederverwendbarkeit von Inhalten. Template-Blöcke sind klar definierte Bereiche innerhalb eines Templates, die durch das `block`-Element gekennzeichnet sind. Sie dienen dazu, einzelne Komponenten der Storefront (z. B. Header, Footer, Navigation) voneinander zu trennen, sodass jede Komponente unabhängig angepasst werden kann. **Beispiel eines Blocks:** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ block header }}

Standard-Header

{{ /block }} ``` ## Template-Blöcke überschreiben Ein Template-Block kann in einem [View-Template](#view-templates-seiten-templates) überschrieben werden, um spezifische Anpassungen für einzelne Seiten vorzunehmen. Dazu wird das `block`-Element einfach mit dem gewünschten Quellcode in das View-Template integriert. Das Basis-Template bleibt dabei unverändert. **Beispiel:** Überschreiben des Headers für die Startseite ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ block "header" }}

Willkommen im Shop!

Das ist unser spezieller Header für die Startseite.

{{ /block }} ``` ### Template-Blöcke erweitern Es ist auch möglich, bestehende Blöcke zu erweitern, ohne deren ursprünglichen Inhalt zu entfernen. Dafür gibt es die Schlüsselwörter `prepend` (Inhalt voranstellen) und `append` (Inhalt anhängen). **Beispiel:** Versandkostenfrei-Banner im Header hinzufügen: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ block "header" append }}

Versandkostenfreiheit ab 50.00 € Einkaufswert

{{ /block }} ``` Mehr Informationen zu den Template-Blöcken sowie deren Verwendung und Anpassung finden sich in der [Referenzdokumentation zu Template-Blöcken](/frontend/referenz/blocke). *** ## View-Templates (Seiten-Templates) View-Templates definieren die individuellen Inhalte für spezifische Shopseiten und sind die einzigen Templates, die von außen per Link adressierbar sind. Sie basieren in der Regel auf einem Basis-Template und verwenden dessen Blöcke, um eine konsistente Struktur und Gestaltung beizubehalten. View-Templates befinden sich im Verzeichnis ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} templates ├── views ``` View-Templates können direkt verlinkt werden, indem ihre URL über den folgenden Befehl generiert wird: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Impressum ``` In diesem Beispiel wird auf das View-Template `impressum.htm` verlinkt. #### Direkter URL-Aufruf eines View-Templates Intern erzeugt `$wsViews.viewUrl()` eine URL mit den Query-Parametern `wsvc=View` und `view=`. Ein View-Template lässt sich damit auch direkt über die Browser-URL aufrufen: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www.beispielshop.de/?wsvc=View&view=impressum.htm ``` | **Parameter** | **Beschreibung** | | ------------- | --------------------------------------------------------------------------------------------------------------------------- | | `wsvc` | Fest auf `View` gesetzt. Weist den Shop an, den View-Controller aufzurufen. | | `view` | Pfad und Dateiname des View-Templates relativ zu `templates/views/`, z. B. `impressum.htm` oder `account/orderHistory.htm`. | Zusätzliche Query-Parameter (z. B. `?wsvc=View&view=account/orderHistory.htm&orderHistorySelect=`) werden an das Template durchgereicht und können dort über `$wsViews.params.` gelesen werden. Verwenden Sie im Template-Code bevorzugt `$wsViews.viewUrl()`, damit URLs korrekt generiert und Änderungen am URL-Schema zentral berücksichtigt werden. Ein View-Template sollte immer ein Basis-Template verwenden. Dadurch wird sichergestellt, dass alle grundlegenden Strukturen wie Header, Footer oder der technische ``-Bereich aus dem Basis-Template übernommen werden. Die Zuweisung erfolgt immer mit dem Befehl `extends`: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ extends "layouts/default.htm" }} ``` Wird mit dem Befehl `extends` ein Basis-Template zugewiesen darf auf dem View-Template ausschließlich mit Blöcken gearbeitet werden. Bei jedem View-Templates kann dann entschieden werden, welche Blöcke des Basis-Templates übernommen, überschrieben oder erweitert werden. Außerhalb von Blöcken darf kein Code stehen. ### System-Templates Es gibt drei vordefinierte System-Templates, die nicht umbenannt oder verschoben werden dürfen: 1. `start.htm`: Definiert die Startseite des Shops. 2. `category.htm`: Template für die Kategorieseiten. 3. `product.htm`: Template für die Produktseiten. Diese Templates sind fester Bestandteil des Systems und dienen als Grundlage für die zentralen Shopseiten. ### CMS-Seitentemplate Statische Inhaltsseiten, deren Inhalte in strapi gepflegt werden (beispielsweise AGB, Impressum, Zahlungsarten, „Über uns"), werden mit einem eigenen View-Template gerendert. Es gilt für alle CMS-Seiten gemeinsam, es gibt kein Template pro Seite. | | | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | Standard-Template | `cms_tpl.htm` | | Konfigurierbar über | `cmsTemplates.template` (siehe [content.cmsTemplates](/konfiguration/content-katalog-kategorien-produkte#content-cmstemplates-cms-seiten)) | | Je Subshop überschreibbar | ja | Im Gegensatz zu den drei System-Templates ist der Name hier frei konfigurierbar. Im Auslieferungszustand ist die Datei nicht enthalten und muss zunächst angelegt werden. Der Aufruf funktioniert nicht über [\$wsViews.viewUrl()](https://dokumentation.websale.de/frontend/referenz/module/wsviews#\$wsviews-viewurl), sondern über die SEO-URL der Seite. Der Shop registriert die Seite, lädt das passende Dokument aus dem Objektspeicher und rendert es mit diesem Template. Wie die Seiten in den Shop gelangen und wie die URL entsteht, ist unter [Auslieferung von CMS-Seiten in den Shop](/strapi-cms/grundlagen-architektur-von-strapi#auslieferung-von-cms-seiten-in-den-shop) beschrieben. #### Das Seitendokument`$wsCmsPage` Das komplette Seitendokument steht 1:1 als `$wsCmsPage` bereit, in derselben Struktur wie die JSON-Datei, ohne Umbenennung oder Umsortierung. Die vollständige Referenz des Moduls steht unter [\$wsCmsPage](/frontend/referenz/module/wscmspage): | **Ausdruck im Template** | **liefert** | | --------------------------------- | -------------------------------------------------------------------------------- | | `$wsCmsPage.contentType` | Content-Typ der Seite, beispielsweise `"api::contentpage.contentpage"` | | `$wsCmsPage.meta.metaTitle` | Meta-Title, beispielsweise `"Zahlungsarten"` | | `$wsCmsPage.meta.metaDescription` | Meta-Description | | `$wsCmsPage.meta.robots` | Liste, beispielsweise `["noindex", "nofollow"]` | | `$wsCmsPage.meta.hreflang` | Liste der Alternativsprachen-Objekte (`language`, `url`, `subshopId`, `default`) | | `$wsCmsPage.meta.publishedAt` | Zeitstempel der Veröffentlichung, `null` bei Entwürfen | | `$wsCmsPage.fields` | Liste der Inhaltsfelder, unverändert aus strapi, je `{ name, type, value }` | Auf allen Seiten, die keine CMS-Seite sind, ist `$wsCmsPage` leer (`null`) und damit im Template als „falsch" prüfbar. Ein gemeinsames Basis-Template kann so gefahrlos auf CMS-Inhalte prüfen: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCmsPage }} {{# nur auf CMS-Seiten #}} {{ /if }} ``` **Inhalte ausgeben.** Die Darstellung von `fields` ist vollständig Aufgabe des Templates. Der Shop liefert nur die Rohdaten und interpretiert sie nicht. Welche Feldnamen und Komponenten es gibt, ergibt sich aus der strapi-Modellierung des jeweiligen Shops. Für den Zugriff wird die Liste einmalig in ein Name/Wert-Objekt überführt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCmsPage }} {{ var $cFields = {} }} {{ foreach $cField in $wsCmsPage.fields }} {{ $cFields[$cField.name] = $cField.value }} {{ /foreach }}

{{= $wsCmsPage.meta.metaTitle }}

{{! $cFields.Markup }}
{{ /if }} ``` Das Muster gilt auf jeder Ebene gleich, auch innerhalb von Komponenten (`value.fields`) und für die Blöcke von Inhaltsblöcken. Ausführlich beschrieben unter [Schritt 4: Feldzugriffe umstellen](/strapi-cms/migration-der-strapi-datenstruktur-v5#schritt-4-feldzugriffe-umstellen) und [Schritt 5: Inhaltsblöcke anpassen](/strapi-cms/migration-der-strapi-datenstruktur-v5#schritt-5-inhaltsblocke-dynamic-zone-anpassen). Behalten Sie beim Rendern der Inhaltsblöcke einen `{{ else }}`-Zweig für unbekannte Komponenten. Sonst verschwindet ein neu angelegter Block still aus der Seite, statt aufzufallen: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ else }} {{ if $wsTestMode.active }} {{ /if }} ``` **SEO-Angaben ausgeben.** Meta-Title und Meta-Description setzt der Shop selbst; sie werden im Basis-Template wie bei allen anderen Seitentypen über [\$wsViews.metaTitle()](https://dokumentation.websale.de/frontend/referenz/module/wsviews#\$wsviews-metatitle) und [\$wsViews.metaDescription()](https://dokumentation.websale.de/frontend/referenz/module/wsviews#\$wsviews-metadescription) ausgegeben. Robots-Angaben und Alternativsprachen rendert das Basis-Template im Auslieferungszustand dagegen nicht. Wer sie braucht, gibt sie im CMS-Seitentemplate selbst aus: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsViews.current.robotOptions }} {{ /if }} {{ foreach $cAlt in $wsCmsPage.meta.hreflang }} {{ /foreach }} ``` [\$wsViews.current.robotOptions](https://dokumentation.websale.de/frontend/referenz/module/wsviews#\$wsviews-current-robotoptions) enthält die Angaben aus `$wsCmsPage.meta.robots` zusammengeführt mit denen aus der Shop-Konfiguration. `$wsCmsPage.meta.hreflang` wird nicht automatisch in die hreflang-Ausgabe des Shops übernommen,[\$wsViews.current.getHreflangAutomatic()](https://dokumentation.websale.de/frontend/referenz/module/wsviews#\$wsviews-current-gethreflangautomatic) liefert für CMS-Seiten nichts aus. ### Benutzerdefinierte Templates Für alle anderen Shopseiten gibt es keine System-Vorgaben. Alle anderen Shopseiten sind frei definierbare View-Templates, die erstellt werden können. Diese können frei benannt werden, z. B.: * `account.htm`: Für das Kundenkonto * `search.htm`: Für die Suche * `impressum.htm`: Für die Impressumsseite * etc. *** ## Components (Includes) Components, auch bekannt als Includes, sind wiederverwendbare Template-Elemente, die flexibel in verschiedenen Bereichen des Shops eingesetzt werden können. Sie dienen dazu, HTML-Code oder andere Anweisungen (z. B. CSS, JavaScript) zu bündeln und an mehreren Stellen im Shop zu nutzen. Im Gegensatz zu Basis-Templates oder View-Templates enthalten Components keine vollständigen HTML-Seitenstrukturen mit `doctype`, `` oder ``, sondern nur ausgewählte Code-Schnipsel. Components befinden sich im Verzeichnis: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} templates ├── components ``` Ein typisches Beispiel für eine Component ist die Produktbox (Vorschauansicht eines Produkts). Diese wird an verschiedenen Stellen im Shop benötigt: * In der **Kategorieübersicht**, um Produkte in einer Liste darzustellen. * In den **Suchergebnissen**, um die Treffer anzuzeigen. * Auf der **Merkliste**, um gespeicherte Produkte darzustellen. * Im **Cross-Selling-Bereich** auf der Produktdetailseite, um verwandte oder empfohlene Produkte anzuzeigen. Anstatt den Code für die Produktbox mehrfach in verschiedenen Templates zu schreiben, wird dieser einmal als Component erstellt, z.B. Components productBox.htm ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}

{{= $myProduct.name }}

Preis: {{= $myProduct.price }} €

Details
``` Anschließend kann die Produktbox überall im Shop eingebunden werden, wo sie benötigt wird – einfach und flexibel über den Include-Befehl: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ include "components/productBox.htm" }} ``` Mehr Details zur Nutzung von Components, zur Übergabe von Produkt- und/oder Kategorieinformationen in die Komponenten sowie weitere Informationen zum Include-Befehl sind in der Referenzdokumentation zu [Template-Blöcken](/frontend/referenz/blocke) und [Components](/frontend/referenz/components) zu finden. *** ## Storefront API Als Alternative zu den Templates kann auch die [Storefront-API](/schnittstellen/storefront-api) genutzt werden, um den Shop aufzubauen. # Zeitabhängige Aktionspreise Source: https://dokumentation.websale.de/frontend/funktionsubersicht/aktionspreise Zeitabhängige Aktionspreise ersetzen den Standardpreis eines Produkts für einen festgelegten Zeitraum. Diese Anleitung zeigt, wie Sie sie im Template ausgeben. Zeitabhängige Aktionspreise sind Preise, die nur innerhalb eines festgelegten Zeitraums gültig sind. Der Shop schaltet zum hinterlegten Zeitpunkt selbst auf den Aktionspreis um und nach dem Ende der Aktion wieder auf den Standardpreis zurück. Im Admin Interface heißt die Funktion Geplante Preise, technisch `scheduledPrices`. Ein einzelner Eintrag wird auf dieser Seite als Aktionspreis bezeichnet. Diese Anleitung beschreibt, wie Sie einen laufenden Aktionspreis im Shop anzeigen. Wo die Preise gepflegt werden, steht am Ende im Abschnitt [Wo Aktionspreise gepflegt werden](#wo-aktionspreise-gepflegt-werden). ## Was im Template zur Verfügung steht | **Feld** | **Inhalt** | | --------------- | ---------------------------------------------------------------------------------- | | `price` | Der aktuell gültige Preis. Läuft eine Aktion, steht hier der Aktionspreis. | | `rawPrice` | Der Standardpreis, unabhängig von laufenden Aktionen. Als Streichpreis verwendbar. | | `promotionInfo` | Der Aktionstext, sofern einer gepflegt wurde. Nur bei laufender Aktion vorhanden. | Diese Felder gehören zum Produktobjekt. Sie stehen daher überall dort zur Verfügung, wo ein Produkt angezeigt wird, also beispielsweise in Kategorielisten, Suchergebnissen, Merklisten und Warenkorbpositionen. Auch jedes weitere Preisfeld des Shops kann eigene Aktionspreise enthalten. Für diese Felder liefert die Funktion `getFullPriceInfo()` dieselben drei Werte. Bei Set-Produkten kommen die Werte `setPrice`, `setRawPrice`, `setOrgPrice`, `setDiscount` und `setDiscountPrice` hinzu. Die Ausgabe von Beginn und Ende einer Aktion stehen im Template noch nicht zur Verfügung. ## Preis mit Streichpreis und Aktionstext ausgeben `rawPrice` ist immer gesetzt, auch wenn keine Aktion läuft. Ohne die entsprechende Prüfung im Template würde an jedem Produkt derselbe Preis zweimal angezeigt, einmal durchgestrichen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $cProduct.rawPrice > $cProduct.price }} {{= $cProduct.rawPrice | currency }} {{= $cProduct.price | currency }} {{ var $cSalePercentage = (($cProduct.rawPrice - $cProduct.price) / $cProduct.rawPrice * 100)|round()|preparedFormat("amount") }} - {{= $cSalePercentage }} % {{ else }} {{= $cProduct.price | currency }} {{ /if }} {{ if $cProduct.promotionInfo }} {{= $cProduct.promotionInfo }} {{ /if }} ``` **Ergebnis**
Während einer laufenden Aktion werden der Standardpreis als Streichpreis, die Ersparnis in Prozent und der Aktionspreis angezeigt. Läuft keine Aktion, wird nur der standardmäßige Preis angezeigt. Der Aktionstext hat eine eigene Bedingung, weil nicht jede Aktion einen gepflegten Aktionstext enthält. ## Wo Aktionspreise gepflegt werden Aktionspreise werden im Admin-Interface auf der Detailseite des Produkts im Reiter "Geplante Preise" mit einer eigenen Tabelle je Preisfeld gepflegt. Ein Eintrag besteht aus dem Preis, dem Zeitraum und optional einem Aktionstext. Mehrere Einträge lassen sich hintereinander stapeln, der Shop schaltet automatisch zwischen ihnen. Die Pflege über die Schnittstelle beschreibt der Abschnitt [Zeitgesteuerte Preise (Aktionspreise)](/schnittstellen/admin-interface-api/api-referenz-produkte#zeitgesteuerte-preise-aktionspreise) der API-Referenz. ## Begriffe und technische Namen | Konzept | Admin Interface | Template | Schnittstelle | | --------------------------- | ----------------------------------- | --------------- | --------------------------------- | | Standardpreis | Feld „Preis“ am Produkt | `rawPrice` | `price.price` | | Aktuell gültiger Preis | — | `price` | — | | Liste der Aktionspreise | Reiter „Geplante Preise“ | — | `price.scheduledPrices` | | Aktionspreis eines Eintrags | Spalte „Preis“ | — | `scheduledPrices[].price` | | Zeitraum | Spalten „Startdatum“ und „Enddatum“ | — | `startDate` und `endDate` | | Aktionstext | Spalte für den Aktionstext | `promotionInfo` | `scheduledPrices[].promotionInfo` | ## Weiterführende Links * [\$wsProducts](/frontend/referenz/module/wsproducts#preis-eines-produkts) beschreibt die Preisfelder am Produktobjekt und `getFullPriceInfo()`. * [\$wsBasket](/frontend/referenz/module/wsbasket) beschreibt den festgeschriebenen Preis einer Warenkorbposition. * [API-Referenz Produkte](/schnittstellen/admin-interface-api/api-referenz-produkte#zeitgesteuerte-preise-aktionspreise) beschreibt das Format der Preisfelder und die Validierung. * [content - Katalog](/konfiguration/content-katalog-kategorien-produkte) beschreibt den Datentyp `price` und das Anlegen weiterer Preisfelder. # Bestellablauf Source: https://dokumentation.websale.de/frontend/funktionsubersicht/bestellablauf Den Bestellablauf in WEBSALE konfigurieren: Anzahl Checkout-Schritte, Adressen, Zahlungsarten, Versandarten und freie Felder flexibel festlegen. Der Bestellablauf ist in WEBSALE frei konfigurierbar und umsetzbar. Das betrifft zum einen die Anzahl der Schritte eines Checkouts, zum anderen die Inhalte, die im Bestellablauf abgefragt und verarbeitet werden, zum Beispiel Adressen, Zahlungsarten, Versandarten, Bestätigungen oder zusätzliche Angaben. *** ## Konfigurationen Folgende Einstellungen sind relevant für die Konfiguration eines WEBSALE Bestellablaufs: ### checkout - Bestellablauf Zentrale Konfiguration des Bestellablaufs, zum Beispiel für Gastbestellung, Vorauswahlen, freie Checkout-Felder, Versandarten und Fehleranzeige. Relevant sind insbesondere: * `checkout.checkout` - Allgemeine Checkout-Einstellungen, Gastbestellung, freie Felder, Standardwerte * `checkout.shippingMethod` - Versandarten im Bestellablauf * `checkout.fieldErrorVisibility` - Fehleranzeige und Fehlerlogik im Checkout * `checkout.checkout.defaults` - Vorauswahlen, z. B. Land, Versandart, Zahlungsart Alle Einstellungsmöglichkeiten siehe [checkout - Bestellablauf](/konfiguration/checkout-bestellablauf)\\ ### customer - Kundendaten Konfiguration der Kundendatenfelder, zum Beispiel für Felddefinitionen, Pflichtfelder, Labels, Feldtypen und Validierungen. Relevant sind insbesondere: * `customer.customerDataField` - Definition einzelner Kundendatenfelder, die abgefragt werden sollen * `customer.customerDataFieldSettings` - Einstellungen und Validierungen der Kundendatenfelder * `customer.customerDataGroup` - Gruppierung von Kundendatenfeldern Alle Einstellungsmöglichkeiten siehe [customer - Kundendaten](/konfiguration/customer-kundendaten) ### accounts - Benutzerkonten Relevant für eingeloggte Kunden, gespeicherte Adressen sowie gespeicherte Bank- oder Zahlungsdaten. Relevant sind insbesondere: * `accounts.addressFieldsSettings` - Einstellungen für Adressfelder * `accounts.addressField` - Definition einzelner Adressfelder * `accounts.customerAddressField` - Zuordnung von Kunden- und Adressfeldern Optional zusätzlich: * `accounts.bankInfoField` - Bankdatenfelder * `accounts.creditCardField` - Kreditkartenfelder Alle Einstellungsmöglichkeiten siehe [accounts - Benutzerkonten](/konfiguration/accounts-benutzerkonten) ### payment - Zahlungsmethoden Konfiguration der angebotenen Zahlungsarten und angebundenen Payment-Provider. Relevant ist insbesondere: * `payment.payment` - Verfügbare Zahlungsarten Je nach eingesetzten Zahlungsarten zusätzlich zum Beispiel: * `payment.payPalCheckout` - Konfiguration für PayPal Checkout * `payment.stripe` - Konfiguration für Stripe bzw. die jeweilige Konfiguration der Zahlungsarten, die im Checkout angeboten werden sollen. Alle Einstellungsmöglichkeiten siehe [payment - Zahlungsmethoden](/konfiguration/payment-zahlungsmethoden) *** ## Module Für die Integration in die Templates sind insbesondere diese Module relevant: * [\$wsCheckout](/frontend/referenz/module/wscheckout) - Checkout-Zustand, Adressen, Versand, Zahlung, Probleme, Summen * [\$wsActions](/frontend/referenz/module/wsactions) - Aktionen erzeugen und auswerten * [\$wsAccount](/frontend/referenz/module/wsAccount) - Login-Status, E-Mail, Adressen, loadAddress() * [\$wsViews](/frontend/referenz/module/wsviews) - Aktuelle URL, Zielseiten, View-URLs * [\$wsBasket](/frontend/referenz/module/wsbasket) - Warenkorb und Bestellübersicht * [\$wsConfig](/frontend/referenz/module/wsconfig) - Konfigurationswerte, zum Beispiel Anreden und Währung Optional zusätzlich, wenn im Checkout eingebunden: * [\$wsPayPalCheckout](/frontend/referenz/module/wspaypalcheckout) - PayPal Checkout * [\$wsStripe](/frontend/referenz/module/wsstripe) - Stripe *** ## Aktionen Für einen Checkout sind - je nach gewünschtem Umfang - insbesondere die unter [Checkout](/frontend/referenz/aktionen/checkout) dokumentierten Aktionen relevant. Alle Aktionen für den Bestellablauf siehe [Checkout](/frontend/referenz/aktionen/checkout) *** ## Zusätzlich relevant für einen OnePage Checkout Wenn alle Checkout-Bereiche auf einer Seite zusammengeführt werden, sind insbesondere diese Punkte relevant: * [MultiActions](/frontend/referenz/aktionen) - Mehrere Aktionen mit einem Klick auslösen * [\$wsCheckout.draftBillAddressId](/frontend/referenz/module/wscheckout) - “Zwischenspeichern” der Rechnungsadresse ohne wirkliches Speichern * [\$wsCheckout.draftShippingAddressId](/frontend/referenz/module/wscheckout) - “Zwischenspeichern” der Lieferadresse ohne wirkliches Speichern * [checkout.fieldErrorVisibility](/konfiguration/checkout-bestellablauf) - Fehleranzeige und Fehlerlogik im Checkout * [checkout.checkout.defaults](/konfiguration/checkout-bestellablauf) - Vorauswahlen, zum Beispiel Land, Versandart oder Zahlungsart Alle genannten Bereiche sind in der jeweiligen Referenzdoku beschrieben und verlinkt. Diese Übersicht dient als technischer Einstiegspunkt für die Umsetzung. # Blättern - Navigation zwischen Produkten Source: https://dokumentation.websale.de/frontend/funktionsubersicht/blaettern-von-produkt-zu-produkt Blätternavigation auf der Produktdetailseite einrichten: Sprung zum vorherigen oder nächsten Produkt innerhalb einer Kategorie inkl. Positionsanzeige. Mithilfe der Blätterfunktion können Besucher auf der Produktdetailseite direkt zum vorherigen oder nächsten Produkt innerhalb der aktuellen Kategorie navigieren. Die Navigation zeigt außerdem die Position des Produkts in der Kategorie an, beispielsweise "4/22". *** ## Module Folgende Module sind für die Integration relevant: * [\$wsViews](/frontend/referenz/module/wsviews) - Aktuelle Seiteninformationen und Produktkontext * [\$wsNavigation](/frontend/referenz/module/wsnavigation) - Navigationspfad (Breadcrumb), liefert die aktuelle Kategorie * [\$wsCategories](/frontend/referenz/module/wscategories) - Lädt alle Produkte einer Kategorie *** ## Frontend-Integration Der folgende Code-Block wird in `components/breadcrumb.htm` direkt nach dem schließenden ``-Tag des bestehende Breadcrumbs eingefügt. Die Blätterfunktion erscheint nur auf Produktseiten. Auf allen anderen Seiten (Kategorie, Suche etc.) wird der Block nicht angezeigt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsViews.current.info.product }} {{ var $cProductId = $wsViews.current.info.product.base.id | ifNull($wsViews.current.info.product.id) }} {{ var $cNavCatId = "" }} {{ foreach $cPart in $wsNavigation.path }} {{ if $cPart.type == "category" }} {{ $cNavCatId = $cPart.object.id }} {{ /if }} {{ /foreach }} {{ if $cNavCatId }} {{ var $cCatProducts = $wsCategories.loadProducts($cNavCatId) }} {{ var $cPrevProduct = null }} {{ var $cNextProduct = null }} {{ var $cCurrentPos = 0 }} {{ var $cCounter = 0 }} {{ var $cTotal = len($cCatProducts) }} {{ foreach $cCatProduct in $cCatProducts }} {{ var $cCompareId = $cCatProduct.base.id | ifNull($cCatProduct.id) }} {{ if $cCompareId == $cProductId }} {{ $cCurrentPos = $cCounter }} {{ /if }} {{ $cCounter = $cCounter + 1 }} {{ /foreach }} {{ if $cCurrentPos > 0 }} {{ $cPrevProduct = $cCatProducts[$cCurrentPos - 1] }} {{ /if }} {{ if $cCurrentPos < $cTotal - 1 }} {{ $cNextProduct = $cCatProducts[$cCurrentPos + 1] }} {{ /if }}
{{ if $cPrevProduct }} {{ else }} {{ /if }} {{= $cCurrentPos + 1 }}/{{= $cTotal }} {{ if $cNextProduct }} {{ else }} {{ /if }}
{{ /if }} {{ /if }} ``` *** ## Weiterführende Links * [\$wsViews](https://dokumentation.websale.de/frontend/referenz/module/wsviews) * [\$wsNavigation](https://dokumentation.websale.de/frontend/referenz/module/wsnavigation) * [\$wsCategories](https://dokumentation.websale.de/frontend/referenz/module/wscategories) # Shop-Modi Source: https://dokumentation.websale.de/frontend/funktionsubersicht/inaktiv-seite Shop-Modi eines Subshops verstehen: Aktiv, Inaktiv und Wartung umschalten und damit den öffentlichen Zugriff auf den Onlineshop steuern. Jeder Subshop besitzt einen Betriebsstatus, der steuert, ob er öffentlich erreichbar ist. Administratoren können den Modus über die Admin-Oberfläche wechseln. Die Umstellung wirkt sich sofort auf alle Besucher aus. *** ## Verfügbare Modi Ein Subshop befindet sich stets in einem der folgenden Modi. | Modus | Zugriff | Typischer EInsatz | | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | | Aktiv | Jeder. | Normaler Live-Betrieb. | | Testmodus | Nur Besucher, die sich über den [Testmodus-Login](https://dokumentation.websale.de/konfiguration/general-allgemeine-shopeinstellungen#general-testmode-testmodus) authentifizieren. | Test und Abnahmen vor dem Live-Gang.
Testprodukte werden sichtbar. | | Inaktiv | Niemand - jede Anfrage wird auf eine kurze "Shop nicht verfügbar"-Seite umgeleitet. | Shop noch nicht gestartet oder abgeschaltet. | *** ## Modus wechseln (Admin-Interface) Pfad: *Admin → Konfiguration → Subshops* In der Subshop-Tabelle gibt es eine Spalte namens "Status", die den aktuellen Modus jedes Subshops anzeigt. Jede Zeile Besitzt ein Kontextmenü, dessen Einträge sich am aktuellen Status orientieren - es werden nur die vom aktuellen Zustand aus sinnvollen Übergänge angezeigt: * **Live schalten** - in den Modus Aktiv wechseln. * **In Testmodus setzen** - in den Testmodus wechseln. * **Deaktivieren** - in den Modus Inaktiv wechseln. Websale Doku Set Testmode ### Liveschaltung Vor jeder Änderung führt die Auswahl **Live schalten** eine Bereitschaftsprüfung durch. Dabei werden alle aktiven Online-Zahlungsarten geprüft und jede gemeldet, die sich noch im Sandbox-Modus befindet. Alle Prüfungen wurden bestanden - Der Shop wird auf **Aktiv** gesetzt und es erscheint eine Erfolgsmeldung. Die Tabelle wird neu geladen und die Zeile zeigt den neuen Status. Ein Blocker wurde gefunden - Es wird keine Änderung übernommen. Eine Fehlermeldung ("Live-Schaltung blockiert") listet jeden blockierenden Dienst und den Grund (z.B. PayPal: Sandbox). Beheben Sie den Blocker und versuchen Sie es erneut. ### In den Test- oder Inaktiv-Modus wechseln Wenn Sie den Testmodus wählen und die Option **Deaktivieren** auswählen, wird die Änderung direkt übernommen, ohne dass eine Bereitschaftsprüfung durchgeführt wird.

Folgendes passiert nach der Änderung (je nach gewähltem Modi): * **Testmodus**
Der öffentliche Shop ist hinter dem Testmodus-Login gesperrt. Nur authentifizierte Besucher sehen den Shop. Als "Test" markierte Produkte werden sichtbar. Dies ist für die Go-Live-Validierung mit Zahlungsanbietern in einem sicheren Zustand geeignet. Bestellungen, die im Testmodus aufgegeben werden, erhalten automatisch den Verifizierungsstatus `test` . * **Inaktiv**
Jeder Besucher sieht die kurze Seite "Shop ist derzeit inaktiv", unabhängig von der aufgerufenen URL. Details zum Template siehe [hier](#inaktiv-seite). *** ## Bereitschaftsprüfung per API Die Bereitschaftsprüfung kann auch programmatisch ausgelöst werden. Dabei werden dieselben Checks wie bei der Schaltfläche "Live schalten" durchgeführt, der Status wird jedoch nicht geändert. Details zu der Endpoint-Methode und zum anschließenden Setzen des Status sind in der [API-Referenz](https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-shop-modi) zu finden. *** ## Inaktiv-Seite Befindet sich ein Subshop im Inaktiv-Modus, wird jede eingehende Anfrage auf eine eigenständige "Shop nicht verfügbar"-Seite umgeleitet - unabhängig davon, welche URL der Besucher aufgerufen hat. Die Inaktiv-Seite wird aus dem Template `myshop/template/views/inactive.htm` gerendert. `myshop` dient hier als Platzhalter für den eigentlichen Shopnamen. ### Anpassung Wenn Sie die Inaktiv-Seite für einen konkreten Shop anpassen möchten (z.B. Branding, Lokalisierung, Kontaktinformationen), überschreiben Sie dieses Template im Shop-spezifischen [Template-Verzeichnis](https://dokumentation.websale.de/frontend/die-basics). ### Mehrsprachigkeit Eine englische Variante existiert derzeit nicht. Falls benötigt, legen Sie sie unter dem Pfad `templates-english/views/inactive.htm` an. *** ### Gut zu wissen * Der Status ist eine Einstellung pro Subshop (mehr dazu [hier](https://dokumentation.websale.de/konfiguration/general-allgemeine-shopeinstellungen#general-general-allgemeine-basiseinstellungen)). * Statuswechsel sind jederzeit über dasselbe Kontextmenü umkehrbar. * Die Bereitschaftsprüfung wird nur beim Wechsel in den Zustand "**Aktiv**" ausgeführt. Ein Wechsel in den Testmodus oder den inaktiven Modus ist hingegen immer erlaubt. * Der Status kann auch direkt in der [Konfiguration](https://dokumentation.websale.de/konfiguration/general-allgemeine-shopeinstellungen#general-general-allgemeine-basiseinstellungen) auf `"status": "active"` gesetzt werden. In diesem Fall wird die Bereitschaftsprüfung übersprungen, sodass die genannten Checks nicht stattfinden. *** ## Verwandte Themen * [general.general](https://dokumentation.websale.de/konfiguration/general-allgemeine-shopeinstellungen#general-general-allgemeine-basiseinstellungen) - Allgemeine Basiseinstellungen * [general.testMode](https://dokumentation.websale.de/konfiguration/general-allgemeine-shopeinstellungen#general-testmode-testmodus) - Testmodus * [\$wsTestMode](https://dokumentation.websale.de/frontend/referenz/module/wstestmode) - Testmodus-Modul * [API-Referenz Shop-Modi](https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-shop-modi) # PDF-Ansichten Source: https://dokumentation.websale.de/frontend/funktionsubersicht/pdf-ansichten Shop-Seiten serverseitig als PDF ausgeben: mit URL-Parameter wsfilter=pdf Downloads erzeugen und PDF-Links auf Seiten oder in E-Mails bereitstellen. Mit dem URL-Parameter `wsfilter=pdf` kann jede Shop-Seite als PDF ausgegeben werden. Das System interpretiert die aufgerufene URL wie gewohnt, gibt die Seite jedoch nicht als HTML aus, sondern wandelt sie serverseitig in ein PDF-Dokument um. Das Ergebnis kann dem Benutzer direkt im Browser angezeigt oder als Datei zum Download angeboten werden. Dynamisch erzeugte PDFs können derzeit nicht automatisch als E-Mail-Anhang versendet werden. Sie lassen sich aber als Download-Link bereitstellen - auf einer Shop-Seite oder in einer E-Mail (siehe [PDF-Download in einer E-Mail](https://dokumentation.websale.de/frontend/funktionsubersicht/pdf-ansichten#pdf-download-in-einer-e-mail)). *** ## Module Zwingend benötigt wird nur das Modul [\$wsViews](/frontend/referenz/module/wsviews), um [viewUrl()](https://dokumentation.websale.de/frontend/referenz/module/wsviews#\$wsviews-viewurl) und View-Informationen verwenden zu können. Die Verwendung anderer Module hängt vom jeweiligen Seitenkontext ab, aus dem ein PDF erzeugt werden soll. *** ## URL-Parameter | Parameter | Wert | Pflicht | Beschreibung | | -------------- | ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------- | | `wsfilter` | pdf | ja | Gibt die Seite als PDF aus. | | `wsfilterName` | dateiname.pdf | nein | Legt den Dateinamen der erzeugten PDF inklusive .pdf-Endung fest.
Ohne Angabe vergibt das System einen Standardnamen. | *** ## Funktionsweise ### Beliebige Shop-Seite als PDF ausgeben Der einfachste Weg ist, `?wsfilter=pdf` an eine beliebige Shop-URL anzuhängen. Das System rendert dann die aufgerufene Seite inklusive Navigation, Header und Footer und gibt sie als PDF aus. Beispiel für eine Produktseite: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://demo.shop.websale.biz/mein-produkt/?wsfilter=pdf ``` Ein klickbarer Link lässt sich auf jeder Seite wie folgt einbinden: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Diese Seite als PDF herunterladen ``` ### Eigenes Template für die PDF-Ansicht verwenden Wenn die PDF anders aussehen soll als die normale Shop-Seite, zum Beispiel ohne Navigation, Header oder Footer, muss dafür ein eigenes [Template](https://dokumentation.websale.de/frontend/die-basics/template-theme) angelegt werden. Eine PDF-Ansicht ist ein normales [View-Template](https://dokumentation.websale.de/frontend/die-basics/template-theme#4-view-templates-seiten-templates), das wie jedes andere View-Template im Verzeichnis "`templates/views/`" abgelegt und über [\$wsViews.viewUrl()](https://dokumentation.websale.de/frontend/referenz/module/wsviews#\$wsviews-viewurl) verlinkt wird. Um die Ausgabe als PDF zu erzwingen, wird beim Aufruf zusätzlich der Parameter `wsfilter=pdf` übergeben. Beispielaufruf des eigenen Templates als PDF: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Als PDF herunterladen ``` Sollen mehrere PDFs in einem einheitlichen Design angeboten werden, kann ein Layout-Template erstellt werden (z.B. `layouts/pdf.htm`), das Header, Footer und Seitenstruktur vorgibt und von den einzelnen PDF-Views per `extends` eingebunden wird. Wie Layout-Templates funktionieren, wird unter [Template Theme](/frontend/die-basics/template-theme) beschrieben. ### Datenverfügbarkeit im PDF-Template Ein PDF-Template wird serverseitig genauso erzeugt wie eine normale Shop-Seite. Es bietet deshalb denselben Zugriff auf [Module](/frontend/referenz/module) wie jedes andere Shop-Template. Das bedeutet, dass die Daten nicht eigens übergeben oder neu aufgebaut werden müssen. Entscheidend für die Verfügbarkeit der Module ist, in welchem Kontext die PDF erzeugt wird: * **Session- und shopweite Daten** stehen immer zur Verfügung, unabhängig davon, welches Template gerade verwendet wird. Dazu gehören z.B. der Warenkorb ([\$wsBasket](/frontend/referenz/module/wsbasket)), das Kundenkonto samt Adressen ([\$wsAccount](/frontend/referenz/module/wsAccount)) oder Konfigurationswerte ([\$wsConfig](/frontend/referenz/module/wsconfig)). Ein Warenkorb-PDF kann den Warenkorb also beispielsweise direkt über [\$wsBasket](/frontend/referenz/module/wsbasket) auslesen. * Seitenkontext-bezogene Daten - beispielsweise das aktuell aufgerufene Produkt oder die aktuelle Kategorie - sind an den jeweiligen Seitenkontext gebunden und über [\$wsViews.current.info](https://dokumentation.websale.de/frontend/referenz/module/wsviews#\$wsviews-current-info) erreichbar. Ein Produkt-PDF muss daher aus dem Kontext des jeweiligen Produkts heraus erzeugt werden, damit die Produktdaten geladen werden. *** ## Beispiele ### Warenkorb als PDF ausgeben Um im Warenkorb eine PDF-Version der Warenkorbseite anzubieten, wird ein PDF-Template benötigt, das den Warenkorb darstellt, sowie einen Download-Link, über den dieses Template als PDF aufgerufen werden kann. Der Download-Link wird in das Template der Warenkorbseite eingebunden (z.B. `basket.htm` der genaue Name hängt davon ab, wie die Warenkorbseite im jeweiligen Shop benannt wurde. Er ruft das PDF-Template auf und hängt `wsfilter=pdf` an. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Warenkorb als PDF herunterladen ``` Das zugehörige PDF-Template (hier `views/pdf/basket.htm`) liest die Warenkorb-Daten direkt über [\$wsBasket](/frontend/referenz/module/wsbasket) aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}

Warenkorb

{{ foreach $cItem in $wsBasket.items }} {{ /foreach }}
Produkt Menge Preis
{{= $cItem.product.name }} {{ if $cItem.product.custom.brand }} {{= $cItem.product.custom.brand }}
{{ /if }} {{= $cItem.product.name }} {{ foreach $cVarAttr in $cItem.product.variantSelection | keys }}
{{= $cVarAttr }}: {{= $cItem.product.variantSelection[$cVarAttr] }} {{ /foreach }}
{{= $cItem.quantity | preparedFormat('amount') }} {{= $cItem.total | currency }}
{{ if $wsBasket.shippingCosts > 0 }} {{ /if }}
Zwischensumme {{= $wsBasket.subTotal | currency }}
Versandkosten {{= $wsBasket.shippingCosts | currency }}
Gesamtsumme
``` ### Bestelleingangsbestätigung als PDF bereitstellen Ein häufiger Anwendungsfall ist es, dem Kunden nach einer erfolgreichen Bestellung eine PDF-Bestelleingangsbestätigung anzubieten. Wie jede andere PDF-Ansicht wird sie über ein PDF-Template (hier abgelegt unter`views/pdf/bestellbestaetigung.htm`), das die Bestelldaten darstellt und mit dem Parameter `wsfilter=pdf` aufgerufen wird, erzeugt. Da die Bestelldaten an den Kontext der abgeschlossenen Bestellung gebunden sind, wird der Download-Link auf der Bestellbestätigungsseite platziert, die der Kunde direkt nach dem Bestellabschluss sieht. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}

Bestelleingangsbestätigung

Vielen Dank für Ihre Bestellung.

Rechnungsadresse

{{ var $cBillAddress = $wsAccount.loadAddress($wsCheckout.selectedBillAddress) }} {{= $cBillAddress.firstName }} {{= $cBillAddress.lastName }}
{{= $cBillAddress.street }} {{= $cBillAddress.streetNumber }}
{{= $cBillAddress.zip }} {{= $cBillAddress.city }}
{{= $cBillAddress.country }} {{ if $wsCheckout.selectedBillAddress != $wsCheckout.selectedShippingAddress }}

Lieferadresse

{{ var $cShippingAddress = $wsAccount.loadAddress($wsCheckout.selectedShippingAddress) }} {{= $cShippingAddress.firstName }} {{= $cShippingAddress.lastName }}
{{= $cShippingAddress.street }} {{= $cShippingAddress.streetNumber }}
{{= $cShippingAddress.zip }} {{= $cShippingAddress.city }}
{{= $cShippingAddress.country }} {{ /if }}

Versandart

{{ foreach $cShipping in $wsConfig.shippingMethods }}{{ if $wsCheckout.selectedShippingMethod == $cShipping.id }}{{= $cShipping.name }}{{ /if }}{{ /foreach }}

Zahlungsart

{{ foreach $cPayment in $wsConfig.payments }}{{ if $wsCheckout.selectedPayment == $cPayment.id }}{{= $cPayment.name }}{{ /if }}{{ /foreach }} {{ foreach $cFreeField in $wsCheckout.freeFields }} {{ if $cFreeField.id == "comment" and $cFreeField.text }}

{{= $cFreeField.name }}

{{= $cFreeField.text }} {{ /if }} {{ /foreach }} ``` Der Download-Link wird auf der Bestellbestätigungsseite platziert, die der Kunde direkt nach dem Bestellabschluss sieht: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Bestelleingangsbestätigung als PDF herunterladen ``` ### PDF-Download-Link in einer E-Mail PDF-Dateien können als Download Link in E-Mail-Templates (z.B. der Bestellbestätigungs-E-Mail) zur Verfügung gestellt werden. Dabei wird das PDF nicht an die E-Mail angehängt, sondern beim Klick auf den Link in der E-Mail erzeugt. Der Link wird nach dem bereits bekannten Schema gebildet. Dabei sind zwei Dinge wichtige: der Typ "`absolute`", weil E-Mails vollständige URLs benötigen und die Parameter, die den Inhalt eindeutig identifizieren (z.B. `voucherId`, `productId`. So kann das PDF unabhängig von der Session erzeugt werden. Beispiel: Download-Links im E-Mail-Template für gekaufte Gutscheine, das versendet wird, nachdem Gutscheine über den Shop gekauft wurden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $basketItem in $wsBasket.items }} {{ if $basketItem.product.custom.voucherProductActive }} {{ foreach $voucherId in $basketItem.voucherIds }} Gutschein {{= $voucherId }} herunterladen {{ /foreach }} {{ /if }} {{ /foreach }} ``` In diesem Beispiel ist `voucher/default_voucher.htm` das PDF-Template, das die Gutschein-Daten anhand der übergebenen `voucherId` und `productId` ausgibt. *** ## Weiterführende Links * [Template-Theme](https://dokumentation.websale.de/frontend/die-basics/template-theme#basis-template-layout-template) # Produktvergleich Source: https://dokumentation.websale.de/frontend/funktionsubersicht/produktvergleich Der Produktvergleich lässt Kunden mehrere Produkte derselben Kategorie nebeneinander vergleichen. Diese Anleitung zeigt, wie Sie ihn im Template einrichten. Der Produktvergleich sammelt Produkte in einer sitzungsweiten Liste und stellt sie auf einer eigenen Vergleichsseite tabellarisch gegenüber. Ein Kunde fügt Produkte von der jeweiligen Produktdetailseite aus hinzu und ruft dann die Vergleichsseite auf. Dort sieht er alle Felder der ausgewählten Produkte in einer Tabelle nebeneinander. Zeilen, in denen sich die Werte unterscheiden, können farblich hervorgehoben werden. Um sinnfreie Vergleiche (beispielsweise eine Hose neben einem Laptop) zu vermeiden, erlaubt der Shop nur Produkte derselben Kategorie in der Vergleichsliste. Die Kategorie wird über ein Produktfeld festgelegt. Die Funktion ist eine Template-Erweiterung und keine Kernfunktion des Shopsystems. Es gibt dafür keine eigene Konfiguration im Admin-Interface - die Steuerung erfolgt ausschließlich über die hier beschriebenen Template-Dateien. ## Voraussetzungen Damit der Produktvergleich sinnvoll funktioniert, muss das Kategoriefeld am Produkt gepflegt sein. Fehlt es, lassen sich Produkte weiterhin vergleichen, allerdings ohne Schutz vor kategorieübergreifenden Vergleichen. Der Shop benötigt ein freies Produktfeld, das die Kategorie eines Produkts als Text enthält (beispielsweise `Bekleidung`, `Elektronik`, `Katzenfutter`). Im BestPractice-Shop trägt dieses Feld den technischen Namen `mainCategory`. Ist das Feld bei einem Produkt leer, wird dieses Produkt beim Hinzufügen zu einer bestehenden Vergleichsliste abgelehnt, sobald die Liste bereits eine Kategorie festgelegt hat (siehe [Wie der Produktvergleich funktioniert](#wie-der-produktvergleich-funktioniert)). Der technische Feldname ist entscheidend, nicht der im Admin-Interface angezeigte Label-Name. Lässt sich der Name nicht auf Anhieb bestimmen, hilft eine Ausgabe aller freien Felder eines Produkts auf der Produktseite: `{{= $cProduct.custom | json }}`. Die Ausgabe zeigt alle technischen Feldnamen mit ihren aktuellen Werten. ## Begriffe und technische Namen auf einen Blick | Konzept | Session | Template (product.htm / compare.htm) | | ---------------------------------- | ------------------------------------- | ------------------------------------------------------------------ | | Liste der verglichenen Produkt-IDs | `compareIds` (kommagetrennter String) | `$compareIds` (als Array aufbereitet) | | Aktuell festgelegte Kategorie | `compareType` | `$compareType` | | Kategorie eines Produkts | — | `$cProduct.custom.mainCategory` | | Aktion zum Schreiben der Session | — | `$wsActions.create("SessionUpdate")` | | Vergleichsseite (eigene View) | — | `views/compare.htm`, Aufruf über `$wsViews.viewUrl('compare.htm')` | Die Session speichert `compareIds` als kommagetrennten String (`"123,456,789"`), nicht als Array. Grund dafür ist, dass `$wsSession.set()` bei einem leeren Array keinen Wert schreibt; ein leerer String lässt sich dagegen zuverlässig speichern und auslesen. Im Template wird der String bei jedem Aufruf über `split(",")` wieder in ein Array zerlegt. ## Wie der Produktvergleich funktioniert Beim Versuch, ein Produkt zur Vergleichsliste hinzuzufügen, prüft der Shop die Kategorie in folgender Reihenfolge: 1. **Die Liste ist leer.** Das Produkt wird unabhängig von seiner Kategorie aufgenommen. Seine Kategorie (`mainCategory`) wird dabei als sitzungsweite Vergleichskategorie (`compareType`) festgelegt. 2. **Die Liste enthält bereits Produkte und die Kategorie des neuen Produkts stimmt mit der festgelegten Vergleichskategorie überein.** Das Produkt wird aufgenommen. 3. **Die Kategorie stimmt nicht überein (oder ist am Produkt leer).** Das Produkt wird nicht aufgenommen. Auf der Produktseite erscheint an Stelle des „Hinzufügen"-Links ein Hinweistext mit der aktuell geltenden Kategorie. Wird die Liste vollständig geleert (letztes Produkt entfernt oder über „Vergleich leeren"), wird auch die festgelegte Vergleichskategorie zurückgesetzt. Danach kann der Kunde erneut mit einer beliebigen Kategorie beginnen. Zusätzlich ist die Liste auf eine bestimmte Anzahl an Produkten begrenzt, die im Template beliebig angepasst werden kann. Ist das Limit erreicht, erscheint statt des „Hinzufügen"-Links ein entsprechender Hinweis. Die maximale Anzahl der vergleichbaren Produkte ist im Template-Code fest hinterlegt (`len($compareIds) >= 4`) und keine Einstellung im Admin-Interface. Ein anderer Grenzwert lässt sich nur durch Ändern dieser Zahl direkt im Template erreichen. ## Anzeige im Shop ### Button auf der Produktdetailseite Auf der Produktseite erscheint je nach Zustand einer von vier Varianten: | Zustand | Anzeige | | ---------------------------------------------------------- | -------------------------------------------------- | | Produkt ist bereits in der Liste | Link „Bereits im Vergleich – entfernen" | | Kategorie weicht von der festgelegten Kategorie ab | Hinweistext mit der geltenden Kategorie, kein Link | | Die Liste enthält bereits die maximale Anzahl an Produkten | Hinweis „Max. Produkte im Vergleich erreicht" | | Keiner der obigen Fälle | Link „Zum Vergleich hinzufügen" | ### Badge im Header Im Header zeigt ein Icon mit Zähler die aktuelle Anzahl der verglichenen Produkte an und verlinkt auf die Vergleichsseite. Der Zähler erscheint nur, wenn mindestens ein Produkt in der Liste ist. ### Vergleichsseite Die Vergleichsseite (`views/compare.htm`) listet alle Produkte der aktuellen Vergleichsliste in einer Tabelle: eine Produktkarte pro Spalte (Bild, Name, Preis, Link zur Produktseite), darunter Preis, Artikelnummer, Beschreibung, Kategorie und alle weiteren gepflegten freien Felder. Felder, die bei keinem der verglichenen Produkte einen Wert tragen, werden nicht angezeigt. Zeilen, in denen sich die Werte unterscheiden, werden farblich hervorgehoben, damit Unterschiede auch bei vielen Feldern auf einen Blick erkennbar sind. Ist die Liste leer, erscheint ein Leerzustand mit einem Link zurück zum Shop. ## Module Für die Umsetzung des Produktvergleichs werden folgende Module verwendet: * [\$wsSession](/frontend/referenz/module/wssession) - Speichern und Auslesen der Vergleichsliste (`compareIds`) und der festgelegten Kategorie (`compareType`). * [Aktionen - Übersicht](/frontend/referenz/aktionen) - Aktion `SessionUpdate`, um die Session vor dem Rendern der Seite zu schreiben. * [\$wsProducts](/frontend/referenz/module/wsproducts) - Laden der Produktdaten für jede ID in der Vergleichsliste auf der Vergleichsseite. ## Einrichtung Der Produktvergleich betrifft drei Template-Dateien: die Produktdetailseite (`product.htm`), den Header (`header.htm` bzw. die eingebundene Header-Komponente) und eine neu anzulegende Vergleichsseite (`views/compare.htm`). Die folgenden Schritte bauen aufeinander auf und sollten in dieser Reihenfolge umgesetzt werden. ### Schritt 1: Kategoriefeld am Produkt bereitstellen Legen Sie, falls noch nicht vorhanden, ein freies Produktfeld für die Kategorie an (siehe [Voraussetzungen](#voraussetzungen)). In dieser Anleitung heißt das Feld `mainCategory`. Pflegen Sie es bei allen Produkten, die am Vergleich teilnehmen sollen. #### Benutzerdefiniertes Feld anlegen Falls solch ein Feld in Ihrem Shop noch nicht existiert, können Sie es wie folgt im Admin-Interface anlegen. 1. Unter *Katalog → Produkte → Einstellungen → „+ Neu"* kann ein neues Produktfeld angelegt werden. Websale Admin Produktfeld Hinzufuegen 2. Vergeben Sie einen eindeutigen technischen Namen für Ihr Produktfeld und speichern Sie es. Websale Admin Produktfeld Hinzufuegen Speichern 3. Anschließend ist das Feld am Produkt verfügbar und kann befüllt werden. In diesem Beispiel wird der Produkttyp **Flyer** verwendet, passend zum Produkt **Flyer Option 1**. Websale Admin Produktfeld Hinzufuegen Eintragung #### Feld an Produkten pflegen Damit die Kategorieprüfung zuverlässig funktioniert, muss das Feld bei allen Produkten mit einem Wert befüllt sein. Produkte ohne Wert werden vom Vergleich ausgeschlossen, sobald bereits ein Produkt mit einem Wert in der Vergleichsliste liegt. | Situation | Verhalten | | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Erstes Produkt in der Vergleichsliste hat den Wert „Bekleidung" | Kategorie wird als Vergleichstyp gesetzt.
Ab jetzt wird bei jedem weiteren Produkt geprüft, ob es den gleichen Wert hat und somit auch zum Vergleich hinzugefügt werden kann. | | Weiteres Produkt für die Vergleichsliste hat den Wert „Bekleidung" | Das Produkt kann zur Vergleichsliste hinzugefügt werden. | | Weiteres Produkt hat den Wert „Elektronik" | Das Produkt kann nicht zur Vergleichsliste hinzugefügt werden. Ein entsprechender Hinweis wird am Produkt ausgegeben. | | Weiteres Produkt hat keinen eingetragenen Wert | Das Produkt kann nicht zur Vergleichsliste hinzugefügt werden. Ein entsprechender Hinweis wird am Produkt ausgegeben. | | Vergleichsliste wird geleert | Jedes beliebige Produkt kann als nächstes zur Vergleichsliste hinzugefügt werden. | ### Schritt 2: Vergleichsliste in `product.htm` einlesen Öffnen Sie `product.htm` und fügen Sie ganz oben im Block `content_main`, vor der eigentlichen Seitenausgabe, den folgenden Abschnitt ein. Er liest den aktuellen Stand der Vergleichsliste aus der Session und bereitet ihn für die weitere Verwendung auf: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $compareIdsRaw = $wsSession.get("compareIds") | ifNull("") }} {{ var $compareIds = [] }} {{ if $compareIdsRaw != "" }} {{ foreach $id in split($compareIdsRaw, ",") }} {{ push($compareIds, $id) }} {{ /foreach }} {{ /if }} {{ var $compareTypeRaw = $wsSession.get("compareType") }} {{ var $compareType = "" }} {{ if $compareTypeRaw }} {{ $compareType = $compareTypeRaw }} {{ /if }} ``` **Ergebnis**
`$compareIds` steht ab dieser Stelle als Array von Produkt-IDs zur Verfügung, `$compareType` enthält die aktuell festgelegte Kategorie oder einen leeren String, wenn die Liste leer ist. Beide Variablen werden in den nächsten Schritten benötigt. ### Schritt 3: Button-Bereich in `product.htm` einbauen Fügen Sie an der Stelle, an der der Vergleichs-Button erscheinen soll (beispielsweise unterhalb des Warenkorb-Formulars), folgenden Block ein. Er berechnet je nach Zustand den passenden Formularinhalt und übergibt ihn an die Aktion `SessionUpdate`. Die maximale Anzahl von 4 Produkten (`$maxReached`) kann hier durch Ändern der Zahl an Ihren gewünschten Grenzwert angepasst werden: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $alreadyInCompare = $cProduct.id in $compareIds }} {{ var $maxReached = len($compareIds) >= 4 }} {{ var $productCategory = $cProduct.custom.mainCategory | ifNull("") }} {{ var $typeMismatch = $compareType != "" and $productCategory != "" and $compareType != $productCategory }} {{ var $myActionCompareUpdate = $wsActions.create("SessionUpdate") }}
{{ if $alreadyInCompare }} {{ var $removeIds = [] }} {{ foreach $id in $compareIds }} {{ if $id != $cProduct.id }} {{ push($removeIds, $id) }} {{ /if }} {{ /foreach }} {{ var $removeIdsStr = join($removeIds, ",") }} {{ var $removeTypeStr = $compareType }} {{ if len($removeIds) == 0 }} {{ $removeTypeStr = "" }} {{ /if }}
{{ elseif $typeMismatch }}

Nur „{{= $compareType }}" vergleichbar

{{ elseif $maxReached }}

Max. Produkte im Vergleich erreicht

{{ else }} {{ var $addIds = [] }} {{ foreach $id in $compareIds }} {{ push($addIds, $id) }} {{ /foreach }} {{ push($addIds, $cProduct.id) }} {{ var $addIdsStr = join($addIds, ",") }} {{ var $addTypeStr = $compareType }} {{ if $addTypeStr == "" }} {{ $addTypeStr = $productCategory }} {{ /if }}
{{ /if }}
``` Der umgebende `
` ist erforderlich. Über diese ID ersetzt `wsReplaceIds` beim Absenden des Formulars gezielt diesen Bereich, ohne die restliche Seite neu zu laden. **Ergebnis**
Auf der Produktseite erscheint abhängig vom aktuellen Zustand automatisch der passende Button oder Hinweistext (siehe [Anzeige im Shop](#button-auf-der-produktdetailseite)). ### Schritt 4: Badge im Header einbauen Öffnen Sie die Header-Datei (`header.htm` bzw. die entsprechend eingebundene Komponente Ihres Templates) und fügen Sie im Bereich der übrigen Icons (Merkliste, Warenkorb) folgenden Block ein: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $compareIdsRaw = $wsSession.get("compareIds") | ifNull("") }} {{ var $compareCount = 0 }} {{ if $compareIdsRaw != "" }} {{ foreach $id in split($compareIdsRaw, ",") }} {{ $compareCount = $compareCount + 1 }} {{ /foreach }} {{ /if }} {{# Icon nach Wahl #}} {{ if $compareCount > 0 }}
{{= $compareCount }}
{{ /if }}
``` Auch hier ist die umgebende ID (`wsCompareHeaderBadge`) erforderlich, damit der Zähler beim Hinzufügen oder Entfernen eines Produkts per AJAX aktualisiert wird (siehe `wsReplaceIds` in Schritt 3 und Schritt 5). **Ergebnis**
Im Header erscheint ein Icon mit Zähler, das auf die Vergleichsseite verlinkt. Der Zähler aktualisiert sich beim Hinzufügen oder Entfernen eines Produkts ohne Neuladen der Seite. ### Schritt 5: Vergleichsseite anlegen Legen Sie eine neue Datei `views/compare.htm` an. Sie ist eine eigenständige View und wird über `{{= $wsViews.viewUrl('compare.htm') }}` aufgerufen (siehe Schritt 4). Die Datei liest zunächst den Session-Stand ein - identisch zu Schritt 2: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $compareIdsRaw = $wsSession.get("compareIds") | ifNull("") }} {{ var $compareIds = [] }} {{ if $compareIdsRaw != "" }} {{ foreach $id in split($compareIdsRaw, ",") }} {{ push($compareIds, $id) }} {{ /foreach }} {{ /if }} {{ var $compareTypeRaw = $wsSession.get("compareType") }} {{ var $compareType = "" }} {{ if $compareTypeRaw }} {{ $compareType = $compareTypeRaw }} {{ /if }} ``` Darauf folgt der übrige HTML-Aufbau der Seite (``, eigenes `` mit Stylesheet, ``). Da `compare.htm` eine eigenständige View ist, wird kein Shop-Layout eingebunden - Kopf- und Fußbereich der Seite müssen, sofern gewünscht, selbst ergänzt werden. Innerhalb des Seitenkörpers folgt zunächst der „Vergleich leeren"-Button: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if len($compareIds) > 0 }} {{ var $myActionCompareClear = $wsActions.create("SessionUpdate") }}
{{ /if }} ``` Ist die Liste leer, wird an dieser Stelle ein Leerzustand mit Link zurück zum Shop angezeigt (`{{ if len($compareIds) == 0 }} ... {{ else }} ...`). Andernfalls werden die Produktdaten geladen: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $products = [] }} {{ foreach $id in $compareIds }} {{ var $p = $wsProducts.load($id) }} {{ push($products, $p) }} {{ /foreach }} ``` Für jedes Produkt wird eine Produktkarte mit einem eigenen Entfernen-Button ausgegeben. Da mehrere solcher Formulare auf derselben Seite vorkommen, erhält jede Aktion eine `tag`, um sie voneinander zu unterscheiden: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $p in $products }} {{ var $keepIds = [] }} {{ foreach $id2 in $compareIds }} {{ if $id2 != $p.id }} {{ push($keepIds, $id2) }} {{ /if }} {{ /foreach }} {{ var $keepIdsStr = join($keepIds, ",") }} {{ var $keepTypeStr = $compareType }} {{ if len($keepIds) == 0 }} {{ $keepTypeStr = "" }} {{ /if }} {{ var $myActionCompareRemove = $wsActions.create("SessionUpdate", tag=$p.id) }}
{{# Bild, Name, Preis, Link zur Produktseite folgen hier #}} {{ /foreach }} ``` Der gesamte Seiteninhalt (Button „Vergleich leeren", Leerzustand und Produkttabelle) muss in einen gemeinsamen Container mit der ID `wsCompareWrapper` eingeschlossen werden. Nur so kann `wsReplaceIds` beim Entfernen oder Leeren die komplette Vergleichsseite in einem Zug aktualisieren. **Ergebnis**
Die Vergleichsseite zeigt alle Produkte der Liste mit einem eigenen Entfernen-Button pro Produkt sowie einem Button zum vollständigen Leeren der Liste. ### Schritt 6: Vergleichstabelle mit dynamischen Feldern aufbauen Nach den Produktkarten folgt die eigentliche Vergleichstabelle. Feste Zeilen wie Preis, Artikelnummer und Kategorie werden direkt ausgegeben. Für die übrigen, frei gepflegten Produktfelder wird zunächst ermittelt, welche Feldnamen bei mindestens einem der Produkte einen Wert tragen: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $skipFields = ["image", "mainCategory", "brand", "crossSelling", "crosslinks"] }} {{ var $allKeys = [] }} {{ foreach $p in $products }} {{ foreach $key in keys($p.custom) }} {{ if not ($key in $skipFields) }} {{ if not ($key in $allKeys) }} {{ push($allKeys, $key) }} {{ /if }} {{ /if }} {{ /foreach }} {{ /foreach }} ``` `$skipFields` enthält die Felder, die bereits über eigene, fest formulierte Tabellenzeilen ausgegeben werden (beispielsweise das Bild oder die Kategorie), damit sie nicht ein zweites Mal in der dynamischen Liste erscheinen. Passen Sie diese Liste an die in Ihrem Shop verwendeten Feldnamen an. Für jedes verbleibende Feld wird geprüft, ob mindestens ein Produkt einen Wert trägt, und ob sich die Werte zwischen den Produkten unterscheiden: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $key in $allKeys }} {{ var $hasValue = false }} {{ foreach $p in $products }} {{ if $p.custom[$key] }} {{ $hasValue = true }} {{ /if }} {{ /foreach }} {{ if $hasValue }} {{ var $firstVal = $products[0].custom[$key] | ifNull("") }} {{ var $allSame = true }} {{ foreach $p in $products }} {{ if ($p.custom[$key] | ifNull("")) != $firstVal }} {{ $allSame = false }} {{ /if }} {{ /foreach }} {{= $key }} {{ foreach $p in $products }} {{ if $p.custom[$key] }}{{= $p.custom[$key] }}{{ else }}–{{ /if }} {{ /foreach }} {{ /if }} {{ /foreach }} ``` **Ergebnis**
Felder, die bei keinem der verglichenen Produkte einen Wert tragen, erscheinen nicht in der Tabelle. Zeilen, in denen sich die Werte zwischen den Produkten unterscheiden, erhalten die CSS-Klasse `highlight` und lassen sich damit optisch hervorheben (beispielsweise mit einem farbigen Hintergrund). ## Weiterführende Links * [\$wsSession](/frontend/referenz/module/wssession) - Speichern und Lesen sitzungsweiter Werte. * [Aktionen - Übersicht](/frontend/referenz/aktionen) - Funktionsweise von Aktionen, insbesondere die Verarbeitung vor dem Rendern und die Ausführung per AJAX über `wsReplaceIds`. * [\$wsProducts](/frontend/referenz/module/wsproducts) - Laden einzelner Produkte anhand ihrer ID. * [\$wsViews](/frontend/referenz/module/wsviews) - Erzeugen von View-URLs für eigene Views wie `compare.htm`. # Scan & Order Source: https://dokumentation.websale.de/frontend/funktionsubersicht/scan-and-order Scan & Order im Frontend integrieren: QR- und Barcode-Scanner im Suchfeld nutzen, um Produkte direkt aufzurufen oder in den Warenkorb zu legen. Mithilfe dieser Funktion können Kunden Produkte per QR- oder Barcode aufrufen und in den Warenkorb legen. Ein Scanner-Icon im Suchfeld öffnet die Kamera im Vollbild-Modus. Wird eine URL gescannt, erfolgt einen direkte Weiterleitung. Wird hingegen ein Barcode gescannt, wird das Produkt mit der gescannten ID direkt in den Warenkorb gelegt. *** ## Module Folgende Module sind relevant für die Integration von Scan & Order: * [\$wsViews](/frontend/referenz/module/wsviews) - aktuelle URL, Zielseiten, View-URLs *** ## Frontend-Integration ### Abhängigkeiten Der Scanner basiert auf der Open-Source-Bibliothek [html5-qrcode.](https://github.com/mebjas/html5-qrcode) Die Datei `html5-qrcode.min.js` wird im Verzeichnis `scripts/` abgelegt und erst beim Öffnen des Scanners per Lazy-Load eingebunden. ### QR-Button im Suchfeld Der Button wird direkt vor dem Suchfeld innerhalb der Komponente `ws-search-box` platziert und öffnet den Scanner. Er erscheint, je nach Endgerät, an folgenden Stellen: * in der Desktop-Suchleiste des Headers Image * im mobilen Offcanvas-Navigationsmenü Image
Die Einbindung in den Header erfolgt über die Datei `components/layout/header.htm`: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ... ``` Der Button muss sowohl im Desktop-Header als auch im mobilen Offcanvas-Menü identisch platziert werden. Mithilfe des Attributs` aria-label=%QRCodeBtnTitle%` werden die Shop-Textbausteine für die Barrierefreiheit benutzt. ### Modal-Fenster Das Vollbild-Modal wird einmalig im Basis-Layout eingefügt. Der Bereich` #wsQRScanner` ist dafür zuständig, dass die Kameravorschau von `HTML5-QR-Code` angezeigt wird. Die Einbindung erfolgt über die Datei `layouts/default.htm` : ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` ### JavaScript-Konstante Der Pfad zur Bibliothek wird im `{{ autoescape "js" }}` -Block der Layout-Datei `layouts/default.htm` als JavaScript-Variable gesetzt. ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ autoescape "js" }} {{ var $cAddToBasketTarget = $wsViews.viewUrl("basket.htm") }} {{ var $cAddToBasketParams = { wscsrf: $wsActions.csrfToken, quantity: 1 } }} {{ var $cAddToBasketLink = $wsActions.url("BasketItemAdd", $cAddToBasketTarget, $cAddToBasketParams) }} {{ /autoescape }} ``` ### Scanner-Logik Der folgende Code-Block ist in die Datei `scripts/wsGlobal.js` einzufügen. Der Ablauf ist wie folgt: 1. Beim ersten Öffnen des Scanners wird `html5-qrcode.min.js` nachgeladen. 2. War die Bibliothek bereits geladen, wird der Scanner direkt über `wsInitQRScan()` gestartet. 3. `html5-qrcode` startet die Kamera und zeigt die Vorschau im `#wsQRScanner` -Bereich an. 4. Nach erfolgreichem Scan leiten URL-Codes direkt zur gescannten URL weiter - Barcodes legen das Produkt mit der gescannten ID direkt in den Warenkorb. 5. Beim Schließen des Fensters wird die Kamera gestoppt. ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} // ---------------------------------------------------------- QR code scanner - start // const html5QrCode and function wsInitQRScan is in script html5-qrcode.min.js function wsInitQRScan() { Html5Qrcode.getCameras().then(devices => { if (devices && devices.length) { // use this to start scanning html5QrCode.start( { facingMode: "environment" }, { fps: 10, qrbox: { width: 250, height: 250 } }, (decodedText, decodedResult) => { // do something when code is read html5QrCode.stop().then((ignore) => { // QR Code scanning is stopped if (decodedText.startsWith("http")) { // execute QR code if code is a URL location.href = decodedText; } else { // execute WEBSALE search if Barcode location.href = wsAddToBasketLink + "&productId=" + decodedText; } }).catch((err) => { // Stop failed, handle it }); }, (errorMessage) => { // parse error, ignore it }) .catch((err) => { // Start failed, handle it } ); } }).catch(err => { // access denied }); } document.querySelector("#wsQRCodeScanModal").addEventListener("show.bs.modal", function(e) { var wsQRCodeScanScript = document.querySelector("#wsQRCodeScanScript"); if (!wsQRCodeScanScript) { // lazyload script for better performance var script = document.createElement("script"); script.setAttribute("id", "wsQRCodeScanScript"); script.setAttribute("src", wsQRCodeJS); document.head.appendChild(script); } else { // execute function if script is already loaded wsInitQRScan(); } }); document.querySelector("#wsQRCodeScanModal").addEventListener("hidden.bs.modal", function(e) { html5QrCode.stop().then((ignore) => { // QR Code scanning is stopped }).catch((err) => { // Stop failed, handle it }); }); // ---------------------------------------------------------- QR code scanner - end ``` *** ## Weiterführende Links * [html5-qrcode auf GitHub](https://github.com/mebjas/html5-qrcode) - Dokumentation und Konfigurationsoptionen der Scanner-Bibliothek # Storefinder Source: https://dokumentation.websale.de/frontend/funktionsubersicht/storefinder Storefinder mit Click & Collect umsetzen: Stores anlegen, Marktauswahl in der Session speichern und Verfügbarkeiten im gewählten Markt anzeigen. WEBSALE unterstützt einen Storefinder beziehungsweise Filialfinder inklusive Click & Collect, Speicherung des ausgewählten Marktes und Verfügbarkeitsprüfung im gewählten Markt. Kunden können damit einen Markt auswählen, sich diesen Markt für die Session merken und - sofern unterstützt - Ware online bestellen und im Markt abholen. *** ## Store-Verwaltung Aktuell ist die Verwaltung der Stores nur über die REST API Stores möglich.
Eine Verwaltung der Stores über das Admin Interface wird gerade entwickelt und steht zu erst zu einem späteren Zeitpunkt zur Verfügung. Damit ein Storefinder im Onlineshop angeboten werden kann, müssen Stores angelegt und gepflegt werden. Die Verwaltung der Stores erfolgt aktuell über die [API-Referenz Stores](/schnittstellen/admin-interface-api/api-referenz-stores). Dort sind auch die verfügbaren Felder eines Stores dokumentiert, wie zum Beispiel: * `name` - Name des Marktes * `street` - Straße und Hausnummer * `openingHours` - Öffnungszeiten * `location` - Koordinaten des Marktes * `clickAndCollect` - Abholung im Markt verfügbar * und viele mehr Alle Datenfelder für einen Store siehe [API-Referenz Stores](/schnittstellen/admin-interface-api/api-referenz-stores)
*** ## Konfiguration ### checkout - Bestellablauf Nur relevant, wenn ein Store im Bestellablauf als Abholort angeboten werden soll, also für Click & Collect. * `checkout.shippingMethod` - Versandarten im Bestellablauf, relevant ist insbesondere `type` für den Versandarttyp, z. B. `standard` oder `pickup` Alle Einstellungsmöglichkeiten siehe [checkout - Bestellablauf](/konfiguration/checkout-bestellablauf) *** ## Module Für die Integration der Filial-, Markt- oder Storeauswahl im Shop sind insbesondere diese Module relevant: * [\$wsStores](/frontend/referenz/module/wsstores) - Märkte laden, Marktlisten ausgeben, ausgewählten Markt verwenden * [\$wsActions](/frontend/referenz/module/wsactions) - Aktionen erzeugen und auswerten, z.B. Markt auswählen * [\$wsViews](/frontend/referenz/module/wsviews) - Aktuelle URL, Zielseiten, View-URLs * [\$wsCheckout](/frontend/referenz/module/wscheckout) - Markt im Checkout, ausgewählte Versandart * [\$wsConfig](/frontend/referenz/module/wsconfig) - Versandarten und weitere Konfigurationswerte * [\$wsInventory](/frontend/referenz/module/wsinventory) - Marktbestand über storageId laden *** ## Aktionen Für den Storefinder sind diese Aktionen relevant: * [Stores](/frontend/referenz/aktionen/stores) - Aktionsreferenz für den Storefinder * [Checkout](/frontend/referenz/aktionen/checkout) - Marktauswahl im Checkout für Versandarten vom Typ `pickup` über `CheckoutStoreIdSelect` # Werbemittelkennzeichen Source: https://dokumentation.websale.de/frontend/funktionsubersicht/werbemittelkennzeichnung Werbemittelkennzeichen ordnen Bestellpositionen einem Werbemittel wie beispielsweise einem Katalog, einer Anzeige oder einem Mailing, zu. Werbemittelkennzeichen, auch Werbemittelcodes genannt, sind kurze Codes, anhand derer sich nachvollziehen lässt, über welches Werbemittel eine Bestellung zustande gekommen ist. Beispiele hierfür sind ein bestimmter Katalog, eine Anzeige oder ein Mailing. Der Code wird an die Produktnummer angehängt, beispielsweise `123456-09` . Dabei steht `123456` für die Produktnummer und `09` für das Werbemittelkennzeichen. In den Bereichen Konfiguration, Templates und Schnittstellen trägt dieses Konzept den technischen Namen `Insert` . Die zugehörigen Felder heißen etwa`content.inserts` (Konfiguration), `validInsertCodes` (gültige Codes je Produkt) und `insert` (Code einer einzelnen Position). Die Tabelle im Abschnitt [Begriffe und technische Namen](#begriffe-und-technische-namen-auf-einen-blick) ordnet alle Namen einander zu. Die vollständigen technischen Details je Ebene (Template-Modul, Konfiguration, REST- und Storefront-API) stehen auf den unter [Weiterführende Links](#weiterführende-links) verlinkten Detailseiten. Die Funktion ist standardmäßig ausgeschaltet. Solange sie nicht aktiviert **und** eingerichtet ist (siehe [Voraussetzungen](#voraussetzungen)), verhält sich der Shop unverändert: keine zusätzlichen Eingabefelder, keine zusätzlichen Anzeigen, nichts wird gespeichert. ## Voraussetzungen Damit ein Werbemittelkennzeichen wirken kann, müssen drei Dinge erfüllt sein. Fehlt auch nur eines davon, bleibt die Funktion für das betroffene Produkt wirkungslos - es erscheint in diesem Fall auch keine Fehlermeldung. 1. **Die Funktion ist aktiviert.** In der Konfiguration muss `content.inserts.enabled` auf `true` stehen. Solange sie aus ist, wird kein Code erfasst, aufgelöst oder angezeigt. 2. **Die Feldzuordnung ist eingerichtet** (einmalig pro Shop). Der Shop muss wissen, welches Produktfeld die gültigen Codes enthält. Diese Zuordnung wird in `content.usedFields.products.validInsertCodes` hinterlegt. Fehlt sie, findet der Shop die am Produkt gepflegten Codes nicht und behandelt jedes Produkt so, als hätte es keine gültigen Codes. 3. **Am Produkt sind gültige Codes gepflegt.** Erst wenn ein Produkt im Feld `validInsertCodes` konkrete Codes trägt, kann für dieses Produkt ein Code übernommen werden. Ist die Liste leer, greift der [Standardcode](#konfiguration) (`defaultInsertCode`), sofern einer konfiguriert ist. Die konkreten Schritte dazu stehen weiter unten im Abschnitt [Einrichtung](#einrichtung). Ohne Feldzuordnung (Punkt 2) wirken die produktspezifischen Codes nicht . Es reicht nicht, das Produktfeld nur anzulegen und Codes einzutragen. Fehlt die Zuordnung in `usedFields.products`, erhält jede Position stillschweigend den Standardcode (oder gar kein Kennzeichen), auch wenn an den Produkten Codes gepflegt sind. ## Begriffe und technische Namen auf einen Blick Je nach Ebene (Admin-Interface, Konfiguration, Template oder Schnittstelle) heißt das Konzept der Werbemittelkennzeichen unterschiedlich. Diese Tabelle ordnet die verschiedenen Bezeichnungen einander zu. | Konzept | Admin Interface | Konfiguration | Template | Schnittstelle | | ---------------------------- | ------------------------------------------------------------------------------ | -------------------------------------- | ------------------------------------- | --------------------------------------- | | Funktion aktiv | `Einstellungen -> Shop-Konfiguration -> Gruppe "Werbemittelkennzeichen"` | `$wsConfig.inserts.enabled` | `enabled` in `GET config/inserts` | | | Standardcode | `Einstellungen -> Shop-Konfiguration -> Gruppe "Werbemittelkennzeichen"` | `content.inserts.defaultInsertCode` | `$wsConfig.inserts.defaultInsertCode` | `defaultInsertCode` in `config/inserts` | | Trennzeichen | `Einstellungen -> Shop-Konfiguration -> Gruppe "Werbemittelkennzeichen"` | `content.inserts.separator` | `$wsConfig.inserts.separator` | `separator` in `config/inserts` | | Position (davor/dahinter) | `Einstellungen -> Shop-Konfiguration -> Gruppe "Werbemittelkennzeichen"` | `content.inserts.position` | `$wsConfig.inserts.position` | `position` in `config/inserts` | | Gültige Codes je Produkt | Feld „Gültige Werbemittelkennzeichen" ([Details](#zulässige-codes-am-produkt)) | `validInsertCodes` (Produktfeld) | — | `custom.validInsertCodes` (Admin-API) | | Feldzuordnung (einmalig) | — | `usedFields.products.validInsertCodes` | — | — | | Code je Warenkorbposition | — | — | `$item.insert` | `insert` (add / update) | | Produktnummer inklusive Code | — | — | `$item.itemNumberWithInsert` | `itemNumberWithInsert` (Response) | | Code an einer URL übergeben | — | — | — | URL-Parameter `insert` | In den gespeicherten Bestelldaten trägt der Code den Namen `insertCode` (nicht `insert`). Beim Auslesen einer abgeschlossenen Bestellung ist daher dieser Name maßgeblich. Die genauen Feldnamen je Schnittstelle stehen auf den jeweiligen Detailseiten (siehe [Weiterführende Links](#weiterführende-links)). ## Wie der Shop ein Werbemittelkennzeichen ermittelt Sind die [Voraussetzungen](#voraussetzungen) erfüllt, ermittelt der Shop beim Hinzufügen eines Produkts in den Warenkorb das Werbemittelkennzeichen für diese Position in folgender Reihenfolge: 1. **Ein gültiger Code wurde angegeben** → Der Code wird für das Produkt übernommen. 2. **Kein Code wurde angegeben** → Der Shop versucht, den zuletzt in dieser Sitzung verwendeten Code (das [sitzungsweite Werbemittelkennzeichen](#sitzungsweites-werbemittelkennzeichen)) zu übernehmen, sofern er für dieses Produkt gültig ist. 3. **Andernfalls** → Es greift der in der [Konfiguration](#konfiguration) hinterlegte Standardcode (`defaultInsertCode`). Ist keiner hinterlegt, bleibt die Position ohne Kennzeichen. Die drei Fälle bauen aufeinander auf. Fall 3 greift nur, wenn kein Code angegeben wurde und es keinen passenden Sitzungscode gibt. "Kein Code → Standardcode" ist also keine Absolutregel, sondern der letzte Schritt der Kette. ### Sitzungsweites Werbemittelkennzeichen Sobald ein gültiger Code erkannt wurde, merkt sich der Shop diesen für die laufende Sitzung. Dabei handelt es sich um den in Fall 2 oben beschriebenen Code, der für nachfolgende Produkte ohne eigene Code-Angabe herangezogen wird. Der Code bleibt auch erhalten, wenn ein Artikel zwischendurch aus dem Warenkorb entfernt wird. Gibt der Besucher später auf einem der [Erfassungswege](#wo-ein-code-erfasst-werden-kann) einen weiteren gültigen Code an, tritt dieser an die Stelle des bisherigen. Ab dann gilt der neue Code als sitzungsweites Werbemittelkennzeichen. Ein leerer oder ungültiger Code überschreibt den gemerkten Code hingegen nicht. Mit Abschluss der Bestellung wird der gemerkte Code gelöscht. ### Was bedeutet „gültiger Code" Welche Codes für ein Produkt zulässig sind, legt die [Produktpflege](#zulässige-codes-am-produkt) fest. Die Prüfung erfolgt zeichengenau und unter Beachtung der Groß-/Kleinschreibung. So sind beispielsweise `DA` und `da` nicht dasselbe. ### Speicherung in der Bestellung Das ermittelte Werbemittelkennzeichen wird mit der Bestellung gespeichert und steht damit in der Bestellauswertung als eigene Information zur Verfügung. ## Wo ein Code erfasst werden kann Es gibt drei voneinander unabhängige Wege, auf denen ein Werbemittelkennzeichen in den Shop gelangt. * **Über die URL**: Ein Werbemittelkennzeichen lässt sich per URL-Parameter `insert` an einen Produktaufruf anhängen - ideal für Links aus Katalogen, Anzeigen oder Mailings. Dies ist auf zwei unabhängigen Wegen möglich: * an einer technischen View-URL über die Produkt-ID: `?view=Product&productId=&insert=` * an einer SEO-URL des Produkts: `/buntes-t-shirt?insert=` * **Direktbestellung**: Auf der Direktbestellseite kann pro Eingabezeile ein Feld für das Werbemittelkennzeichen hinzugefügt werden. Dies ist eine Template-Erweiterung. Die Umsetzung ist unter [Beispiele](#werbemittelkennzeichen-in-der-direktbestellung-erfassen) beschrieben. * **Warenkorb (Schnittstelle)**: Beim Hinzufügen oder Ändern eines Postens kann der Code direkt mitgegeben werden - siehe [Storefront-API Warenkorb](/schnittstellen/storefront-api/storefront-api-warenkorb). Eine View-URL ist dabei eine über die Template-Funktion `$wsViews.url(...)` bzw. `$wsViews.viewUrl(...)` erzeugte, technische Shop-URL (im Gegensatz zur sprechenden SEO-URL) - Details siehe [Modul \$wsViews](/frontend/referenz/module/wsviews). Beide URL-Arten nehmen den `insert`-Parameter gleichermaßen an. Wird ein Produkt **ohne** `insert`-Parameter aufgerufen, bleibt ein bereits gesetztes sitzungsweites Werbemittelkennzeichen erhalten - „kein Parameter" wird also nicht wie „kein Code" behandelt. Der Sitzungscode wird erst beim Hinzufügen des Produkts in den Warenkorb herangezogen und dort gegen die gültigen Codes geprüft. ## Praxisbeispiel: von der Anzeige bis zur Bestellung Folgendes Szenario veranschaulicht, wie die Regeln zusammenspielen: Ein Kunde erhält ein Mailing mit einem Produktlink, an den das Werbemittelkennzeichen `09` angehängt ist (beispielswiese`/buntes-t-shirt?insert=09`). Mit einem Klick gelangt er auf die Produktseite. Der Code `09` wird als sitzungsweites Werbemittelkennzeichen gespeichert. Anschließend legt er das T-Shirt in den Warenkorb. Da `09` für dieses Produkt ein gültiger Code ist, trägt die Position das Kennzeichen und die Artikelnummer erscheint als `123456-09`. Anschließend stöbert er weiter und legt eine Hose in den Warenkorb, ohne dabei einen Code aufzurufen. Der Shop zieht den gemerkten Sitzungscode `09` heran. Wenn `09` auch für die Hose gültig ist, wird auch diese Position mit `09` gekennzeichnet. Andernfalls greift der Standardcode oder die Position bleibt ohne Kennzeichnung. Beim Wechsel zur Kasse und dem Abschluss der Bestellung wird das ermittelte Kennzeichen jeder Position zusammen mit der Bestellung gespeichert. Anschließend wird die Sitzung beendet und der gemerkte Code `09` wird verworfen. In der Bestellhistorie steht das gespeicherte Kennzeichen zwar in den Bestelldaten (als `insertCode`), die fertig zusammengesetzte Anzeige `itemNumberWithInsert` ist dort jedoch nicht verfügbar. Wie sich das Kennzeichen in der Bestellhistorie darstellen lässt, ist unter [Beispiele → Bestellhistorie](#bestellhistorie) beschrieben. ## Sonderfälle **Set-Artikel:** Der Code wird sowohl für die Hauptposition als auch für die enthaltenen Unterartikel aufgelöst. Jeder Unterartikel prüft den Code gegen seine eigenen gültigen Codes (sonst greift der Standardcode). Das funktioniert genauso wie bei einem einzeln hinzugefügten Artikel. **Varianten:** Die zulässigen Codes werden auf Ebene des Hauptprodukts gepflegt und gelten gleichermaßen für dessen Varianten. Beim Hinzufügen einer Variante wird das sitzungsweite Kennzeichen gegen die gültigen Codes des Hauptprodukts geprüft. ## Einrichtung Dieser Abschnitt beschreibt die konkreten Schritte zu den unter [Voraussetzungen](#voraussetzungen) genannten Bedingungen. ### Konfiguration Die Einstellungen liegen im Konfigurationsbereich unter (`content.inserts`): | **Einstellung** | **Bedeutung** | **Standard** | | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | | `enabled` | Schaltet die gesamte Funktion ein bzw. aus. | aus | | `defaultInsertCode` | Wird verwendet, wenn kein oder ein ungültiger Code erfasst wurde. Leer lassen, wenn in diesem Fall gar kein Kennzeichen gesetzt werden soll. | leer | | `separator` | Zeichen zwischen Produktnummer und Code, beispielsweise `-`. | `-` | | `position` | Steht der Code hinter der Produktnummer (`123456-09`) oder davor (`09-123456`). | dahinter | Solange `enabled` deaktiviert ist, bleibt die Funktion im gesamten Shop wirkungslos - unabhängig davon, wie die einzelnen Produkte gepflegt sind. Hinweis zu `defaultInsertCode`: Der Standardcode greift produktübergreifend für jede Eingabe, die nicht zu einem gültigen Code aufgelöst werden kann. Wer den Code auf einen festen Wert setzt, sollte bedenken, dass dieser Wert dann auch für Posten verwendet werden kann, für die eigentlich kein Werbemittelkennzeichen vorgesehen ist. Im Zweifel sollten Sie den Wert leer lassen. ### Produktfeld anlegen Ist das Feld `validInsertCodes` im Shop noch nicht vorhanden, wird es einmalig als benutzerdefiniertes Produktfeld angelegt. Im Admin Interface geschieht das im Bereich Katalog → Produkte über die Produktfelder-Einstellungen (Einstellungen / Zahnrad rechts oben anwählen). Die dortige Tabelle zeigt alle vorhandenen Produktfelder mit Name, Typ und maximaler Länge. Über die Schaltfläche **Neu** wird das Feld mit folgenden Einstellungen angelegt: | **Einstellung** | **Wert** | | --------------- | ------------------------------ | | Name | `validInsertCodes` | | Label | Gültige Werbemittelkennzeichen | | Typ | Liste (Texteinträge) | | Maximale Länge | 16 Zeichen je Eintrag | Alternativ kann das Feld über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) im Knoten `content.customProductField` erstellt werden. ### Feldzuordnung einrichten Nach dem Anlegen des Produktfelds muss es einmalig der Funktion zugeordnet werden. Erst durch diese Zuordnung weiß der Shop, in welchem Produktfeld die gültigen Werbemittelkennzeichen stehen. Die Zuordnung wird im Konfigurationsknoten [content.usedFields](/konfiguration/content-katalog-kategorien-produkte#content-usedfields-zuordnung-benutzerdefinierter-felder) gepflegt. Im Bereich `products` verweist der Eintrag `validInsertCodes` auf das angelegte Produktfeld: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "products": { "validInsertCodes": "content.customProductField.validInsertCodes" } } ``` Das Beispiel zeigt nur den relevanten Eintrag. Der Knoten enthält daneben die Zuordnungen aller anderen Funktionsbereiche (beispielsweise `weight`, `crossSelling`, `metaTitle`). Diese bestehenden Einträge bleiben unverändert erhalten, es wird ausschließlich der Wert von `validInsertCodes` gesetzt. Ohne diese Zuordnung wirken die am Produkt gepflegten Codes nicht. Der Shop kann die gültigen Codes eines Produkts dann nicht ermitteln, und jeder Posten erhält stillschweigend den Standardcode oder bleibt ohne Kennzeichen, auch wenn an den Produkten Codes gepflegt sind. Es reicht also nicht, das Produktfeld nur anzulegen, es muss auch zugeordnet werden. ### Zulässige Codes am Produkt Das Feld „**Gültige Werbemittelkennzeichen**" (`validInsertCodes`) ist ein benutzerdefiniertes Produktfeld und wird im Admin Interface auf der Detailseite des jeweiligen Produkts gepflegt. Wie jedes benutzerdefinierte Feld erscheint es in der Feldgruppe, der es zugeordnet wurde - andernfalls in der Sammelgruppe „Sonstige". Über dieses Feld wird pro Produkt festgelegt, welche Codes für dieses Produkt erlaubt sind. Es handelt sich um ein Listenfeld. Jeder gültige Code wird als eigener Eintrag erfasst. Ein Trennzeichen wird nicht benötigt und die Codes werden nicht als zusammenhängende Zeichenkette gepflegt. Folgende Voraussetzungen gelten für das Anlegen eines Codes: * Jeder Eintrag darf maximal 16 Zeichen lang sein. * Jeder Code ist ein eigener Listeneintrag. Die Codes werden nicht durch Kommas oder andere Trennzeichen in einem Feld aneinandergereiht. * Die Codes sind case-sensitiv (beispielsweise ist `DA` nicht gleich `da`). * Das Feld wird auf Ebene des Hauptprodukts gepflegt und gilt für dessen Varianten mit. * Ist die Liste leer, kann für dieses Produkt kein Code übernommen werden (es greift höchstens der [Standardcode](#konfiguration), sofern gesetzt). Im Template steht das Feld als Liste zur Verfügung, beispielsweise über `$cProduct.custom.validInsertCodes` auf der Produktseite oder `$item.product.custom.validInsertCodes` an der Warenkorbposition. Die Ausgabe erfolgt per Schleife oder mit `join` und frei wählbarem Trennzeichen: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $cProduct.custom.validInsertCodes | join(", ") }} ``` **Ergebnis**
Die gültigen Codes des Produkts werden kommagetrennt angezeigt, beispielsweise `DA, 09`. ## Anzeige im Shop Das Werbemittelkennzeichen kann als Teil der Artikelnummer im Warenkorb, in der Bestellübersicht, in der Bestätigungs-E-Mail, im Bestell-PDF und in der Bestellhistorie angezeigt werden (beispielsweise `123456-09`) - in der konfigurierten Reihenfolge und mit dem konfigurierten Trennzeichen. Voraussetzung ist, dass die Ausgabe im jeweiligen Template eingebunden ist (siehe [Beispiele](#beispiele)). Die Anzeige setzt sich aus der am Produkt gepflegten Artikelnummer (`itemNumber`) und dem Code zusammen. Ist am Produkt keine Artikelnummer gepflegt, erscheint nur der Code. Wird ein unbekannter Code eingegeben, verwirft der Shop diesen und greift, sofern eingerichtet, auf den Standardwert zurück. Dadurch wird die Bestellung nie blockiert. ## Module Für die Ausgabe des Werbemittelkennzeichens im Template werden diese Module verwendet: * [\$wsConfig](/frontend/referenz/module/wsconfig) - liefert über `$wsConfig.inserts` die aktuellen Einstellungen (aktiv, Trennzeichen, Position, Standardcode) und wird benötigt, um Ausgaben nur bei aktiver Funktion anzuzeigen. * [\$wsBasket](/frontend/referenz/module/wsbasket) - liefert je Warenkorbposition das Kennzeichen über `$item.insert` und die fertige Anzeige über `$item.itemNumberWithInsert`. Die Erfassung eines Codes (URL, Direktbestellung, Warenkorb-Schnittstelle) benötigt kein eigenes Modul, dies geschieht über URL-Parameter, das Direktbestellformular oder die [Storefront-API](/schnittstellen/storefront-api/storefront-api-warenkorb). ## Beispiele ### Artikelnummer mit Werbemittelkennzeichen ausgeben Im Warenkorb (und analog dazu in der Bestellübersicht, der E-Mail und dem PDF) genügt es, `itemNumberWithInsert` als Artikelnummer auszugeben. Die Reihenfolge und das Trennzeichen sind darin bereits berücksichtigt. Wenn kein Code gesetzt ist, enthält das Feld die reine Produktnummer. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $item in $wsBasket.items }}

Art.-Nr.: {{= $item.itemNumberWithInsert }}

Produktname: {{= $item.product.name }}

{{ /foreach }} ``` **Ergebnis**
Jede Position zeigt ihre Artikelnummer inklusive Werbemittelkennzeichen, sofern eines erfasst wurde. Andernfalls wird die reine Produktnummer angezeigt. ### Werbemittelkennzeichen als eigenes Feld ausgeben Wenn der reine Code zusätzlich als eigenes Feld erscheinen soll, prüfen Sie zuerst, ob die Funktion aktiv ist. Andernfalls erscheint bei ausgeschalteter Funktion nichts. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsConfig.inserts.enabled }} {{ foreach $item in $wsBasket.items }} {{ if $item.insert }}

Werbemittelcode: {{= $item.insert }}

{{ /if }} {{ /foreach }} {{ /if }} ``` **Ergebnis**
Der Werbemittelcode erscheint nur bei aktiver Funktion und nur für Positionen, die einen Code tragen. ### Werbemittelkennzeichen in der Direktbestellung erfassen Auf der Direktbestellseite (Template `modules/directOrder.htm`, Modul [\$wsDirectOrder](/frontend/referenz/module/wsdirectorder)) geben Kunden Produktnummern zeilenweise ein. Standardmäßig ist dort kein Eingabefeld für das Werbemittelkennzeichen vorhanden, es muss pro Eingabezeile ergänzt werden. Fügen Sie das folgende Feld in jede Eingabezeile des Formulars ein, und zwar neben dem bestehenden Feld `name="id"`. Entscheidend ist der Feldname `insert`: Darüber liest der Shop den Code ein und löst ihn beim Übernehmen in den Warenkorb gegen die für das jeweilige Produkt gültigen Codes auf (siehe [Wie der Shop ein Werbemittelkennzeichen ermittelt](#wie-der-shop-ein-werbemittelkennzeichen-ermittelt)). Über `{{ if $wsConfig.inserts.enabled }}` erscheint das Feld nur, wenn die Funktion aktiv ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsConfig.inserts.enabled }}
{{ /if }} ``` **Ergebnis**
Pro Zeile erscheint neben der Produktnummer ein Eingabefeld für das Werbemittelkennzeichen. Der eingegebene Code wird zusammen mit der Zeile erfasst und beim Übernehmen in den Warenkorb wieder aufgelöst. Mit der Funktion `$wsDirectOrder.items[…].insert` wird der bereits erfasste Code nach einem Neuladen der Zeile wieder in das Feld geschrieben. ### Bestellhistorie Die Bestellhistorie arbeitet nicht mit dem Warenkorb, sondern mit den gespeicherten Bestelldaten (`$order.orderList.item`). Das fertig zusammengesetzte Feld `itemNumberWithInsert` steht dort nicht zur Verfügung, sodass die Anzeige im Template aus der Produktnummer, dem Code und den Werten aus `$wsConfig.inserts` (Position und Trennzeichen) selbst zusammengesetzt werden muss. ## Weiterführende Links * [\$wsConfig](/frontend/referenz/module/wsconfig) - Einstellungen über `$wsConfig.inserts` (aktiv, Trennzeichen, Position, Standardcode). * [\$wsBasket](/frontend/referenz/module/wsbasket) - Ausgabe je Position über `$item.insert` und `$item.itemNumberWithInsert`. * [\$wsViews](/frontend/referenz/module/wsviews) - Erzeugung von View-URLs (`url()`, `viewUrl()`), an die sich der `insert`-Parameter anhängen lässt. * [content - Katalog](/konfiguration/content-katalog-kategorien-produkte) - Konfigurationsblock `content.inserts` und die zwingende Feldzuordnung `usedFields.products`. * [API-Referenz Produkte](/schnittstellen/admin-interface-api/api-referenz-produkte) - Pflege der zulässigen Codes je Produkt (`custom.validInsertCodes`); setzt die Feldzuordnung `usedFields.products` voraus (siehe [Voraussetzungen](#voraussetzungen)). * [API-Referenz Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) - Pflege des Konfigurationsblocks `content.inserts` über die Konfigurationsknoten-Endpunkte. * [Storefront-API Warenkorb](/schnittstellen/storefront-api/storefront-api-warenkorb) - Setzen und Auslesen des Kennzeichens über das `insert`-Feld sowie `GET /api/v1/config/inserts`. # Übersicht - Zahlungsarten Source: https://dokumentation.websale.de/frontend/funktionsubersicht/zahlungsarten Grundprinzip der Zahlungsarten-Konfiguration: Knoten unter payment.payment anlegen, Aktivierung, Bezeichnungen, Icons und Validierungen festlegen. ## Grundprinzip Jede Zahlungsart wird zunächst als eigener Konfigurationsknoten unter `payment.payment.` angelegt. Die ID ist frei wählbar; es gibt keine fest vorgegebenen Bezeichnungen pro Zahlungsart. Dadurch können Zahlungsarten beispielsweise unter Knoten wie `payment.payment.bill`, `payment.payment.applepay`, `payment.payment.googlepay` oder `payment.payment.paypal` definiert werden. In `payment.payment` werden unter anderem festgelegt, ob die Zahlungsart aktiv ist, welche Bezeichnung sie im Checkout trägt, welches Bild oder Icon verwendet wird und welche Regeln und Einschränkungen für ihre Verfügbarkeit gelten. Die offizielle Doku beschreibt `payment.payment` genau als den Bereich, in dem Zahlarten zusammengefasst und Eigenschaften wie `active`, `id`, `name`, `image`, `validations` sowie die Anbindung an Online-Clearing konfiguriert werden. Typische Angaben einer Zahlungsart sind zum Beispiel: * Aktiv-/Inaktiv-Schaltung * Name und Beschreibung * Bild oder Icon * Zulässigkeit oder Ausschluss für bestimmte Länder * Zulässigkeit oder Ausschluss für bestimmte Produkte oder Warenkörbe * Zusätzliche Eingabefelder oder Prüfungen * Art der Zahlungsabwicklung Weitere Informationen zu den allgemeinen Konfigurationsmöglichkeiten einer Zahlungsart finden sich auf der Seite [payment - Zahlungsmethoden](/konfiguration/payment-zahlungsmethoden). *** ## Offline- und Online-Zahlungsarten Für die Konfiguration ist zunächst wichtig, zwischen **offline** und **online** abgewickelten Zahlungsarten zu unterscheiden. Die Doku nennt für `type` ausdrücklich typische Werte wie `offline` für manuell abgewickelte Zahlungen und `online` für Zahlungen über einen Provider. ### Offline-Zahlungsarten Bei einer reinen Offline-Zahlungsart ist die Konfiguration mit `payment.payment.` im Regelfall abgeschlossen. Die Zahlungsart wird angelegt, benannt und im Checkout angeboten, ohne dass eine zusätzliche Provider-Anbindung erforderlich ist. Ein typisches Beispiel dafür ist **Vorauskasse**. Hier reicht die Definition der Zahlart in `payment.payment.prepayment`, da keine Echtzeit-Kommunikation mit einem Zahlungsdienstleister notwendig ist. **Beispielkonfiguration** `payment.payment.prepayment` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "basicCost": null, "description": "Text", "discount": 0, "displayedPaymentTypes": [], "freeFields": null, "id": "prepayment", "image": "", "labels": null, "name": "Vorauskasse", "onlineClearing": null, "orderText": "Text", "provider": "", "type": "", "validations": [ ] } ``` ### Online-Zahlungsarten Bei Online-Zahlungsarten wird die Zahlungsart ebenfalls zunächst unter `payment.payment.` angelegt. Die Zahlungsart selbst bleibt immer zunächst eine eigenständige Konfiguration unter `payment.payment.ID`. Erst wenn sie online abgewickelt werden soll, kommt zusätzlich eine passende Online-Anbindung hinzu, in dem bei dem die Zahlungsart beim Parameter `onlineClearing` mit einem konkreten Provider verknüpft wird, z.B. `payment.paypal-checkout` **Beispielkonfiguration** `payment.payment.GooglePay` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": false, "basicCost": null, "description": "Text", "discount": 0, "displayedPaymentTypes": [], "freeFields": null, "id": "paypalCheckoutGooglePay", "image": "", "labels": null, "name": "GooglePay", "onlineClearing": { "options": { "type": "googlePay", "view": "paypal_checkout_pending.htm" }, "service": "payment.paypal-checkout" }, "orderText": "Text", "provider": "", "type": "", "validations": [ ] } ``` # stripe Source: https://dokumentation.websale.de/frontend/funktionsubersicht/zahlungsarten/stripe Zahlungsart Stripe im Checkout einrichten: relevante Konfigurationen, Module wie $wsStripe und $wsCheckout sowie Aktionen für den Bestellprozess. ## Konfigurationen Folgende Einstellungen sind relevant für die Konfiguration der Zahlungsart stripe: *** ## Module Folgende Module sind relevant für die Integration der Zahlungsart stripe im Bestellprozess: * [\$wsStripe](/frontend/referenz/module/wsstripe) - stripe-Zahlungsarten Modul * [\$wsCheckout](/frontend/referenz/module/wscheckout) - Checkout-Zustand, Adressen, Versand, Zahlung, Probleme, Summen * [\$wsActions](/frontend/referenz/module/wsactions) - Aktionen erzeugen und auswerten * [\$wsAccount](/frontend/referenz/module/wsAccount) - Login-Status, E-Mail, Adressen, loadAddress() * [\$wsViews](/frontend/referenz/module/wsviews) - Aktuelle URL, Zielseiten, View-URLs * [\$wsBasket](/frontend/referenz/module/wsbasket) - Warenkorb und Bestellübersicht * [\$wsConfig](/frontend/referenz/module/wsconfig) - Konfigurationswerte, zum Beispiel Anreden und Währung *** ## Aktionen Folgende Aktionen sind relevant für die Integration der Zahlungsart stripe: *** ## Zusätzliche relevante Informationen Folgende zusätzlichen Inhalte müssen für die Zahlungsart integriert werden. ### Frontend-Integration Stripe stellt ein eigenes JavaScript-SDK bereit, das in das Template eingebunden werden muss. Es übernimmt die Darstellung der Zahlungsfelder und die Kommunikation mit Stripe. **HTML-Struktur**
Folgender HTML-Block muss im Template plaziert werden: * `#wsStripePaymentElement` ist der Container, in den Stripe die Zahlungsfelder (z.B. Kreditkartennummer, PayPal-Button etc.) automatisch einbettet * Das Formular sendet beim Klick auf “Mit Stripe bezahlen” den Bezahlvorgang ab ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
``` **JavaScript**
Der folgenden Script-Block muss direkt nach dem HTML-Block eingefügt werden. Er muss in `{{ autoescape “js” }}` eingeschlossen sein, damit Template-Variablen im JavaScript-Kontext korrekt verarbeitet werden. Der Ablauf im Script ist folgender: 1. **Stripe initialisieren** - Das SDK wird mit den Zugangsdaten aus [\$wsStripe.configuration](/frontend/referenz/module/wsstripe) gestartet 2. **Zahlungsfelder anzeigen** - Stripe rendert die Zahlungsauswahl (Kreditkarte, PayPal etc.) in den `#wsStripePaymentElement`-Container. Die Adresseingabefelder von Stripe werden dabei deaktiviert, weil die Adresse des Kunden bereits im Shop bekannt ist und automatisch übergeben wird. 3. **Bezahlung auslösen** - Beim Absenden des Formulars werden die eingegebenen Zahlungsdaten zusammen mit der Rechnungsadresse aus [\$wsAccount](/frontend/referenz/module/wsAccount) an Stripe geschickt. Stripe gibt dafür ein Confirmation-Token zurück. 4. **Token an den Shop senden** - Das Token wird an den Shop übermittelt, der damit den eigentlichen Zahlungsvorgang bei Stripe startet. 5. **Ergebnis verarbeiten** - Schlägt die Zahlung fehl, wird eine Fehlermeldung angezeigt. Ist eine zusätzliche Bestätigung nötig (z.B. 3D Secure), übernimmt Stripe das automatisch. 6. **Weiterleitung** - Nach erfolgreicher Zahlung wird der Kunde zur Bestellbestätigungsseite weitergeleitet. ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ autoescape "js" }} {{ /autoescape }} ``` *** ## Weiterführende Links * Generelle Doku für das Stripe Frontend: [https://docs.stripe.com/js](https://docs.stripe.com/js) # Getting Started Source: https://dokumentation.websale.de/frontend/getting-started Schritt-für-Schritt-Einstieg in einen WEBSALE-Onlineshop: Design anpassen, Produkte und Kategorien anlegen, Zahlungsarten konfigurieren und Shop SEO optimieren. Ein WEBSALE-Onlineshop bietet zahlreiche Möglichkeiten zur individuellen Anpassung und Konfiguration. Damit Sie schnell und effizient starten können, führt diese Anleitung Sie Schritt für Schritt durch die wichtigsten ersten Aufgaben. Von der grundlegenden Shop-Konfiguration über die visuelle Anpassung der Storefront bis hin zur Einrichtung von Produkten, Kategorien und Zahlungsarten – diese Anleitung zeigt Ihnen, wie Sie Ihren Shop optimal einrichten. Jeder Schritt enthält praktische Anleitungen und Erklärungen, damit Sie direkt loslegen können: ### Arbeiten mit GitLab * [Kennenlernen der WEBSALE GitLab Pipeline](/frontend/getting-started/arbeiten-mit-gitlab) ### Design & Branding anpassen * Logo austauschen * Farben und Schriftarten definieren * Startseite und Layout anpassen ### Produkte & Kategorien verwalten * Kategorien strukturieren und organisieren * Produkte anlegen und bearbeiten * Produktbilder und Beschreibungen hinzufügen ### Grundlegende Shop-Konfiguration * Währungen, Steuersätze etc. einrichten * Zahlungsarten konfigurieren * Versandoptionen festlegen ### SEO & Performance optimieren * Meta-Titel, Beschreibungen und URLs anpassen * Bildoptimierung ### Rechtliche Anforderungen berücksichtigen * DSGVO-Konformität sicherstellen * Impressum und Datenschutzrichtlinien ergänzen * Cookie-Banner einrichten ### Tests & Veröffentlichung * Testbestellungen durchführen * Checkout-Prozess überprüfen * Letzte Anpassungen vor dem Livegang vornehmen ### 🚧 **Hinweis: Inhalte in Bearbeitung** 🚧 Diese Seite wird derzeit aktualisiert und um detaillierte Anleitungen zu den einzelnen Schritten erweitert. Die Übersicht bietet bereits einen strukturierten Leitfaden für den Start mit Ihrem WEBSALE-Onlineshop, jedoch sind einige Abschnitte noch in der Bearbeitung. Die fehlenden Inhalte werden **nach und nach ergänzt**, um Ihnen eine umfassende Schritt-für-Schritt-Anleitung zur Verfügung zu stellen. Schauen Sie regelmäßig vorbei, um die neuesten Updates zu erhalten. Vielen Dank für Ihr Verständnis! 😊 # Arbeiten mit GitLab Source: https://dokumentation.websale.de/frontend/getting-started/arbeiten-mit-gitlab Mit dem GitLab-Repository des Shops arbeiten: Zugriff auf gitlab.websale.cloud sowie Versionierung der Layout- und Template-Dateien einrichten. Zu jedem Shop wird im Standard ein eigenes GitLab-Repository mitgeliefert. Dieses Repository dient zur Verwaltung und Versionierung der Layout- und Template-Dateien, die für das Erscheinungsbild des Shops verantwortlich sind. *** ## Zugriff Das WEBSALE GitLab ist unter folgender URL erreichbar: [https://gitlab.websale.cloud](https://gitlab.websale.cloud) Die Zugangsdaten werden beim Bereitstellen des Shops durch die WEBSALE AG übermittelt.\ Für zusätzliche Benutzer kann über das Beauftragungsportal der WEBSALE AG ein weiterer Zugriff beantragt werden. *** ## Einstellungen (Settings → CI/CD → Variables) Im Menü des Projekts unter Settings → CI/CD → Variables sind Umgebungsvariablen für die Shop-Pipeline definiert. ### Editierbare Variablen | **Variable** | **Beschreibung** | | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `AUTO_COMPILE_TEMPLATES` | Steuert, ob Templates nach Veröffentlichung im Main-Branch automatisch kompiliert werden.
- `true`: automatische Kompilierung beim Merge in *main*
- `false`: manuelle Kompilierung über das Admin Interface (Templates & Inhalte → Templates kompilieren). | | `TEMPLATE_COMPILE_URL` | URL des Shops, über die die Kompilierung ausgeführt wird.
Diese URL muss bei Domainänderungen (z. B. Livegang von `shop-test.websale.net` auf `ihr-shop.de`) angepasst werden, da der Kompilierungsdienst nur über die aktive Shopdomain erreichbar ist. | Angaben zu *Type*, *Environment*, *Visibility Flags* und *Key* dürfen für diese Variablen nicht verändert werden. Änderungen an diesen Einstellungen können zu Störungen oder Fehlern der Pipeline führen. ### Readonly Variablen Diese Variablen können aktuell nur durch Mitarbeiter der WEBSALE AG bearbeitet werden. | **Variable** | **Beschreibung** | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `TEMPLATE_COMPILE_PASSWORD` | Passwort des Admin Interface Benutzers, der in `TEMPLATE_COMPILE_USER` hinterlegt ist. | | `TEMPLATE_COMPILE_USER` | Benutzername des Admin Interface Benutzers.
Der `Template_Compile_User` ist ein separater technischer Benutzer im Admin Interface, der ausschließlich für die GitLab Pipeline vorgesehen ist.
Persönliche Admin-Logins werden dadurch nicht in GitLab hinterlegt und bleiben geschützt. | | `S3_TEMPLATES_BUCKET` | `template`-Bucket im S3. | | `S3_MEDIA_BUCKET` | `media`-Bucket im S3. | | `S3_ENDPOINT` | URL des S3-Storages. | | `AWS_DEFAULT_REGION` | Vorgegebene S3-Region von WEBSALE. | | `AWS_SECRET_ACCESS_KEY` | Zugangsdaten für den Zugriff auf den S3-Speicher. | | `AWS_ACCESS_KEY_ID` | Zugangsdaten für den Zugriff auf den S3-Speicher. | *** ## Verzeichnis- & Dateistruktur (Root-Ebene) Das Repository enthält auf Root-Ebene folgende Einträge im Standard: * `media/` (Verzeichnis) * `templates/` (Verzeichnis) * `.gitlab-ci.yml` (Datei) * `README.md` (Datei) ### media Das Verzeichnis `media` enthält alle statischen Ressourcen, die für das Design und Layout des Shops verwendet werden. Es ist im Standard wie folgt aufgebaut: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} media └── themes └── default ├── favicon ├── fonts │ └── bootstrap ├── images ├── pdf ├── scripts └── scss ``` | **Verzeichnis** | **Beschreibung** | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `favicon` | Icons und Favicons für den Browser | | `fonts` | Schriftdateien (z. B. Bootstrap-Fonts) | | `images` | Layoutgrafiken (z. B. Logos, Icons, Banner) | | `pdf` | Statische PDF-Dateien (z. B. AGBs oder Datenschutzerklärung) | | `scripts` | JavaScript-Dateien | | `scss` | SCSS-Quelldateien für CSS Die kompilierten CSS-Dateien, die aus SCSS generiert werden, sind nicht Bestandteil des Repositories. Diese Dateien können bei Bedarf zu Debug-Zwecken über den Browser bzw. die Browserkonsole eingesehen werden. | Unterhalb des Verzeichnisses `media/` können Ordner und Dateien nach Bedarf umbenannt, gelöscht oder neu angelegt werden. Diese Änderungen werden von der Pipeline beim Deployment berücksichtigt. Beim Umbenennen oder Verschieben bestehender Ordner müssen ggf. auch die entsprechenden Pfadangaben in Templates, Stylesheets oder Skripten angepasst werden, damit Ressourcen weiterhin korrekt geladen werden. ### templates Das Verzeichnis `templates` enthält die für das Shop-Frontend relevanten Template-Dateien. Es ist im Standard wie folgt aufgebaut: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} templates ├── components ├── layouts ├── mails └── views ``` | **Verzeichnis** | **Beschreibung** | | --------------- | --------------------------------------------------------------- | | `components` | Wiederverwendbare Template-Bausteine, HTML-Snippets und Widgets | | `layouts` | Grundlayouts und Seitenstrukturen | | `mails` | E-Mail-Vorlagen | | `views` | Ansichten einzelner Shopseiten | Unterhalb des Verzeichnisses `templates/` können Ordner und Dateien nach Bedarf umbenannt, gelöscht oder neu angelegt werden. Diese Änderungen werden von der Pipeline beim Deployment berücksichtigt. Beim Umbenennen oder Verschieben bestehender Ordner müssen ggf. auch die verwendeten Pfade in den Templates angepasst werden, damit die entsprechenden Includes, Layouts und Views weiterhin gefunden werden. ### gitlab-ci.yml Diese Datei definiert die CI/CD-Pipeline (Continuous Integration / Deployment) in Gitlab. **Standardinhalt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ### DO NOT EDIT THIS FILE! ### ### CHANGES CAN DESTROY THE SHOP! ### include: - remote: 'https://websale.de/git-design/ws_design/templates.yml' ``` Die hinter `remote:` angegebene Datei bindet die zentrale Pipeline-Vorlage der WEBSALE AG ein. Diese Remote-Datei kann ausschließlich durch die WEBSALE AG bearbeitet werden. ### Funktionsweise der WEBSALE Pipeline Die Pipeline wird ausschließlich durch Commits im `main`-Branch gestartet und führt dabei folgende Jobs aus: 1. **Build (compile-sass)** * Überwacht Änderungen in `media/themes/default/scss/**` * Kompiliert SCSS-Dateien zu CSS (`media/themes/default/styles/`) 2. **Deploy (deploy-css)** * Synchronisiert das CSS-Verzeichnis mit dem entsprechenden S3-Bucket * Ausgenommen sind bestimmte Unterverzeichnisse (z. B. Fonts, Scripts, Favicons) 3. **Deploy (deploy-media-without-css)** * Synchronisiert den übrigen `media`-Ordner (ohne Styles-Verzeichnis) mit dem S3-Bucket 4. **Deploy (deploy-templates)** * Überträgt das Verzeichnis `templates` in den S3-Bucket * Führt optional (abhängig von `AUTO_COMPILE_TEMPLATES`) die Template-Kompilierung über die API des Shops durch Der Status der Pipeline sowie Log-Ausgaben der einzelnen Jobs können im GitLab unter **Build → Pipelines** eingesehen werden. ### README.md Datei mit weiterführenden Informationen zum WEBSALE GitLab und dem WEBSALE Shopsystem. *** ## Eigene Versionsverwaltung verwenden Verfügen Sie bereits über eine eigene Versionsverwaltung, die Sie für die Entwicklung des WEBSALE-Shops nutzen möchten (z. B. GitHub, eigenes GitLab, o. Ä.), ist dies grundsätzlich möglich. **Funktionsprinzip** * Die Entwicklung findet wie gewohnt in Ihrer bestehenden Versionsverwaltung statt. * Über eine eigene Pipeline (oder manuell per Git-Remote) werden die relevanten Dateien in das zugehörige WEBSALE GitLab-Projekt übertragen und dort in den Branch `main` gepusht bzw. gemerged. * Ab diesem Zeitpunkt greift die im WEBSALE GitLab-Projekt hinterlegte Pipeline und übernimmt wie gewohnt Build und Deployment (z. B. SCSS-Kompilierung, Medien- und Template-Deployment auf S3). Für das Pushen in das WEBSALE GitLab-Projekt werden folgende Voraussetzungen benötigt: * Ein GitLab-Benutzer für das betreffende WEBSALE Shop-Projekt mit Schreibrechten auf das Projekt bzw. den Branch `main`. Der notwendige Zugang wird durch die WEBSALE AG bereitgestellt. Die Verwendung eines eigenen Repositories ersetzt nicht die Einrichtung des WEBSALE GitLab-Projekts. Die initiale Einrichtung des Projekts und der Benutzer kann derzeit nicht vollständig selbstständig vorgenommen werden und erfolgt vorerst über die WEBSALE AG. *** ## Hinweise & Einschränkungen * Über das GitLab-Repository besteht kein Zugriff auf Produktdaten (z. B. Produkte, Preise, Bilder) oder Kundendaten. Produkt- und Kundendaten können über das Admin Interface, [REST APIs](/schnittstellen/admin-interface-api), Connectoren etc. verwaltet werden. * Das Repository dient zur Verwaltung und zum Deployment von Shop-Templates und den dazugehörigen Mediendateien. * Eigene Prozesse wie z. B. Docker-Container, zusätzliche Build-Jobs oder externe Programme sind mit der Standard-Pipeline nicht vorgesehen. * Die Standard-Pipeline arbeitet aktuell ausschließlich im Branch `main`. * Die Deployment-Jobs synchronisieren nur die Verzeichnisse `media` und `templates`. Oberhalb dieser Verzeichnisse angelegte Ordner werden nicht übertragen. *** ## Zugriff auf den Objektspeicher (S3) Über GitLab besteht nur Zugriff auf die Shop-Templates bzw. das Theme/Template-Repository. GitLab ist damit der zentrale Ort für die Versionsverwaltung und die Bearbeitung des Template-Codes (z. B. Anpassungen am Frontend, Layouts, Komponenten, Styles). Neben dem Zugriff über GitLab existiert zusätzlich ein Zugriff auf den Objektspeicher des Shops (S3). Über diesen Zugang erhält man Zugriff auf alle Dateien des Shops, z.B. Produktbilder, [JSON-Dateien](/schnittstellen/externe-datenschnittstelle-datei-bucket-basiert) etc. # Praxisbeispiele - Gutscheine Source: https://dokumentation.websale.de/frontend/praxisbeispiele/gutscheine Praxisbeispiele für Gutscheine in WEBSALE: Eingabeformular mit maximumCount-Check, Validierung, Einlösen im Checkout sowie Download-Links für gekaufte Gutscheine. In diesem Abschnitt finden Sie Praxisbeispiele für die Verwendung von Gutscheinen im Template. Die ersten Beispiele behandeln das Einlösen im Checkout, das letzte die Ausgabe gekaufter Gutscheine. Gutscheine werden im Admin-Interface angelegt. Dies wird auf den Seiten [Gutscheine](/admin-interface/marketing/gutscheine) und [Kaufgutschein-Produkt anlegen](/admin-interface/katalog/produkte/kaufgutschein-produkt) beschrieben. *** ## Gutscheineingabe-Formular mit `maximumCount`-Check Die Eingabe-Form wird nur angezeigt, solange weniger Gutscheine eingelöst sind als erlaubt. Sobald die Höchstgrenze erreicht ist, verschwindet das Formular automatisch. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cActionVoucherAdd = $wsActions.create("VoucherAdd") }} {{ include "components/errorAlert.htm" with $cAction = $cActionVoucherAdd, $cViewEachField = true }} {{ if len($wsVoucher.vouchers) < $wsVoucher.maximumCount }}
{{ /if }} ``` Fehlermeldungen (z.B. "Mindestbestellwert nicht erreicht") werden über `components/errorAlert.htm` definiert und ausgegeben. *** ## Liste eingelöster Gutscheine anzeigen Pro Gutschein wird ein eigenes kleines Formular mit eindeutiger ID ausgegeben. Gültige Gutscheine erscheinen grün, ungültige rot. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsVoucher.vouchers }}

Eingelöste Gutscheine

{{ foreach $cVoucher in $wsVoucher.vouchers }} {{ var $cVoucherIsValid = $cVoucher.valid | ifNull(true) }} {{ var $cActionVoucherDelete = $wsActions.create("VoucherDelete") }}
{{= $cVoucher.id }}
{{ /foreach }} {{ /if }} ``` *** ## Alle eingelösten Gutscheine im Warenkorb ausgeben In diesem Beispiel werden alle eingelösten Gutscheine im Warenkorb ausgegeben. So sieht der Kunde transparent, welche Codes im System sind und welcher davon gerade greift. Nicht wirksame Gutscheine werden nicht in die Liste aufgenommen und werden über eine Fehlermeldung gekennzeichnet. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cVoucherCount = 0 }} {{ if $wsVoucher.vouchers }} {{ foreach $cVoucher in $wsVoucher.vouchers }} {{ $cVoucherCount = $cVoucherCount + 1 }}
{{ if $cVoucherCount == 1 }}Gutschein{{ else }}Weiterer Gutschein{{ /if }}
{{= $cVoucher.id }}
-{{= $cVoucher.value | currency }} {{ /foreach }} {{ /if }} ``` *** ## Gutscheinfehler mit Grund und Gutschein-ID ausgeben Statt eines allgemeinen Hinweises erhält der Kunde hier je Gutschein den konkreten Grund, warum der Gutschein nicht greift. Die Texte stammen aus [`checkout.voucherErrors`](/konfiguration/checkout-bestellablauf#checkout-vouchererrors-fehlertexte-zu-wirkungslosen-gutscheinen), der Fallback auf `code` greift nur, falls kein Text gepflegt ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.isOrderBlockedByIneffectiveVoucher }} {{ /if }} ``` Prüfen Sie `details.voucherId` immer vor der Ausgabe. Die Gutschein-ID fehlt bewusst, wenn der Fehler aus der Summenprüfung der Mindestbestellwerte stammt. Welcher Fehler wann entsteht, steht unter [Wann welcher Fehler entsteht](/konfiguration/checkout-bestellablauf#wann-welcher-fehler-entsteht). *** ## Kostenfreie Versandart für Gutschein-Warenkörbe Enthält ein Warenkorb ausschließlich (Sofort-)Gutscheine, wird kein physischer Versand benötigt. Dafür lässt sich unter [`checkout.shippingMethod`](/konfiguration/checkout-bestellablauf#checkout-shippingmethod-versandarten) eine eigene, immer kostenfreie Versandart anlegen: Die Preisstaffel `basicCost` setzt die Kosten ab einer Zwischensumme von `0` auf `0`, und die Validierung [`shippingMethodValidation.productType`](/konfiguration/validierungs-und-prufservices) mit `rule: deny` sperrt die Versandart, sobald ein reguläres Produkt (Produkttyp `standard`) im Warenkorb liegt - sie ist also nur für reine Gutschein-Warenkörbe wählbar. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "basicCost": [ { "cost": 0, "subtotal": 0 } ], "description": "checkout.shippingMethod.INSTANT_VOUCHER.description", "group": null, "id": "INSTANT_VOUCHER", "image": "", "link": "", "name": "checkout.shippingMethod.INSTANT_VOUCHER.name", "orderText": "checkout.shippingMethod.INSTANT_VOUCHER.orderText", "taxable": true, "type": "standard", "validations": [ { "options": { "rule": "deny", "ruleList": [ "standard" ] }, "service": "shippingMethodValidation.productType" } ], "weightCost": null } ``` Der Wert `standard` in der `ruleList` ist der **Wert des Produkttyp-Feldes** der Produkte (das über `content.usedFields` als Produkttyp definierte Produktdatenfeld) - nicht zu verwechseln mit dem Parameter `type: "standard"` der Versandart selbst. Produkte, bei denen das Produkttyp-Feld nicht gesetzt ist, bestehen die Prüfung immer. `name`, `description` und `orderText` verweisen im Beispiel auf Textbausteine, sodass die Texte je Sprache über den Textbaustein-Dienst gepflegt werden können. *** ## Gekaufte Gutscheine zum Download anbieten Dieses Beispiel gehört nicht zum Einlösen, sondern zum Verkauf: Wurde ein [Kaufgutschein-Produkt](/admin-interface/katalog/produkte/kaufgutschein-produkt) bestellt, erzeugt der Shop beim Bestellabschluss je bestellter Einheit einen Gutscheincode. Die Codes einer Warenkorbposition stehen im Template unter `voucherIds` bereit, das zugehörige PDF wird über den URL-Parameter `wsfilter=pdf` aus dem am Produkt hinterlegten View-Template erzeugt. Der folgende Block gibt je Position und Code einen Download-Link aus. Er eignet sich für die Bestellbestätigungsseite und für das E-Mail-Template der Bestellbestätigung. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $basketItem in $wsBasket.items }} {{ if $basketItem.product.custom.voucherProductActive }} {{ foreach $voucherId in $basketItem.voucherIds }} Gutschein {{= $voucherId }} herunterladen {{ /foreach }} {{ /if }} {{ /foreach }} ``` Der Typ `absolute` erzeugt eine vollständige URL, weil E-Mails keine relativen Links verarbeiten. Die Parameter `voucherId` und `productId` machen den Aufruf unabhängig von der Session, sodass der Link auch später noch funktioniert. `voucher/default_voucher.htm` steht hier stellvertretend für das View-Template, das am Produkt im Feld "HTML-Template" hinterlegt ist. Wie PDF-Ansichten aufgebaut werden, beschreibt [PDF-Ansichten](/frontend/funktionsubersicht/pdf-ansichten). Für die Weiterverarbeitung außerhalb des Shops stehen dieselben Angaben in den Bestelldaten unter `data.orderList.item[].voucher`, siehe [API-Referenz Bestellungen](/schnittstellen/admin-interface-api/api-referenz-bestellungen). # Praxisbeispiele - Verknüpfung mit dem Zahlungsanbieter Source: https://dokumentation.websale.de/frontend/praxisbeispiele/verknuepfung-zahlungsanbieter Praxisbeispiele für die Verknüpfung eines Kundenkontos mit dem Konto beim Zahlungsanbieter in WEBSALE: Verwaltung im Kundenkonto mit Setup- und Create-Aktion, Aufheben der Verknüpfung sowie das Opt-in im Bestellablauf. In diesem Abschnitt finden Sie Praxisbeispiele für die Verknüpfung eines Kundenkontos mit dem Konto beim Zahlungsanbieter. Besteht eine Verknüpfung, muss der Kunde bei Folgebestellungen die Freigabe auf der Seite des Zahlungsanbieters nicht erneut durchlaufen. Welche Zahlungsarten eine Verknüpfung unterstützen, entscheidet der Zahlungsanbieter. Derzeit unterstützt ausschließlich PayPal Checkout diese Funktion, weshalb die Beispiele die Einbindung des PayPal-SDK zeigen. Die Aktionen selbst sind nicht auf einen bestimmten Zahlungsanbieter festgelegt. Die Beispiele gehen davon aus, dass die Zahlungsart die ID `paypalCheckout` hat. *** ## Verknüpfung im Kundenkonto verwalten Die Seite hat zwei Zustände, die über die Funktion [wsAccount.hasPaymentVault() ](/frontend/referenz/module/wsAccount)unterschieden werden: Besteht eine Verknüpfung, wird ein Formular zum Aufheben der Verknüpfung angezeigt. Besteht keine Verknüpfung, wird der PayPal-Button angezeigt. Dieser legt die Verknüpfung in zwei Schritten an: Zunächst holt `PaymentValueSetup` das Setup-Token und anschließend gibt der Kunde die Verknüpfung bei PayPal frei. Zuletzt speichert `PaymentValueCreate` sie. Weil `PaymentVaultCreate` keinen Antwort-Body liefert, lädt das Beispiel die Seite nach dem Erstellen neu. Erst dadurch liefert `hasPaymentVault()` den neuen Zustand. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ extends "layouts/account_layout.htm" }} {{ block content_account_main }} {{ var $ppcData = $wsPayPalCheckout.loadConfigData() }} {{ var $paymentId = "paypalCheckout"}} {{ var $paymentVault = $wsAccount.hasPaymentVault($paymentId) }} {{if not $paymentVault }} {{ /if }}

PayPal Checkout Vaulting verwalten

{{ var $removeVaultAction = $wsActions.create('PaymentVaultRemove') }} {{ if $removeVaultAction.globalErrors }}
    {{ foreach $err in $removeVaultAction.globalErrors }}
  • {{= $err.text | ifNull($err.code) }}
  • {{ /foreach }}
{{ /if }} {{ var $paymentVaultSetupAction = $wsActions.create('PaymentVaultSetup') }} {{ if $paymentVaultSetupAction.globalErrors }}
    {{ foreach $err in $paymentVaultSetupAction.globalErrors }}
  • {{= $err.text | ifNull($err.code) }}
  • {{ /foreach }}
{{ /if }} {{ var $paymentVaultCreateAction = $wsActions.create('PaymentVaultCreate') }} {{ if $paymentVaultCreateAction.globalErrors }}
    {{ foreach $err in $paymentVaultCreateAction.globalErrors }}
  • {{= $err.text | ifNull($err.code) }}
  • {{ /foreach }}
{{ /if }} {{ if $paymentVault }}
PayPal-Verbindung löschen
{{ else }}
PayPal-Verbindung erstellen
{{ /if }} {{ /block }} ``` Das Beispiel ist auf Testbarkeit ausgelegt, nicht auf Produktionsreife. Der JavaScript-Teil sollte vor dem Livebetrieb ausgebaut werden: `onError` gibt Fehler nur auf der Konsole aus, und ein Fehlschlag von `PaymentVaultCreate` bleibt dem Kunden verborgen, weil die Seite unmittelbar danach neu geladen wird und die Aktionsfehler des vorangegangenen POST damit verloren gehen. *** ## Verknüpfung im Bestellablauf anbieten Wenn für die gewählte Zahlungsart bereits eine Verknüpfung besteht, wird die Bestellung direkt darüber bezahlt und der PayPal-Button entfällt. Besteht noch keine Verknüpfung, können Sie dem Kunden anbieten, diese mit der aktuellen Bestellung anzulegen. Dafür genügt das Formularfeld `initPaymentValue` - die Verknüpfung wird dann beim Bestellabschluss automatisch erstellt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ... {{ var $showPPButton = ($wsCheckout.selectedPayment == "paypalCheckout" or $wsCheckout.selectedPayment == "paypalCheckoutSepa" or $wsCheckout.selectedPayment == "paypalCheckoutPayLater") and $wsCheckout.isValid }} ... {{ var $ppcVault = $wsCheckout.selectedPayment == "paypalCheckout" and $wsCheckout.hasPaymentVault() }} {{ $showPPButton = $showPPButton and not $ppcVault}} ... {{ if $showPPButton }} ... {{ if not $ppcData }} Konnte nicht richtig konfigurieren {{ else }}
PayPal Account für zukünftige Zahlungen speichern
{{ /if }} ... {{ /if }} ``` Das Feld wird beim Bestellabschluss ausgewertet. Die Verknüpfung entsteht nur, wenn zusätzlich alle folgenden Bedingungen erfüllt sind: * Der Kunde ist angemeldet. * Es handelt sich nicht um einen Express-Checkout. * Die gewählte Zahlungsart ist die reine PayPal-Zahlung, nicht PayPal SEPA oder PayPal PayLater. * Es besteht noch keine Verknüpfung. Ist eine dieser Bedingungen nicht erfüllt, wird die Bestellung normal abgeschlossen und die Verknüpfung schlicht nicht angelegt, dafür gibt es keinen Fehlercode. Soll dem Kunden das Anlegen zuverlässig angeboten werden, verwenden Sie den Weg über eine eigene Seite im Kundenkonto, siehe [Verknüpfung im Kundenkonto verwalten](#verknupfung-im-kundenkonto-verwalten). # Referenz - Übersicht Source: https://dokumentation.websale.de/frontend/referenz Komplette Referenz der WEBSALE Template-Sprache: Tags, Anweisungen, Module, Funktionen, Modifier und Aktionen für den Aufbau des Shop-Frontends. Referenz ist das zentrale Nachschlagewerk für die Template Engine und die Template-Sprache. Hier sind alle relevanten Sprachelemente und Bausteine dokumentiert, die für den Aufbau und die Anpassung des Shop-Frontends auf Basis von Templates benötigt werden – zum Beispiel Tags/Anweisungen, Variablen, Funktionen, Modifier und typische Verwendungsformen. Diese Referenz richtet sich an Projekte, die das Shop-Frontend mit Templates umsetzen. Soll das Frontend stattdessen über die Storefront API aufgebaut werden (z. B. Headless-Ansatz), ist diese Seite nicht der richtige Einstieg – in diesem Fall sind die Seiten zur [Storefront API](/schnittstellen/storefront-api/storefront-api-basics) relevant. ## Inhaltsverzeichnis * [Aktionen](/frontend/referenz/aktionen) * [Anweisungen](/frontend/referenz/anweisungen) * [Blöcke](/frontend/referenz/blocke) * [Components](/frontend/referenz/components) * [Conditions](/frontend/referenz/conditions) * [Datentypen](/frontend/referenz/datentypen) * [Funktionen](/frontend/referenz/funktionen) — Globale Template-Funktionen stehen in allen Templates zur Verfügung. Sie werden verwendet, um Werte zu verarbeiten, zu formatieren oder zu prüfen (z. B. Strings anpassen, Zahlen runden, Listen zusammenführen oder Datumswerte vergleichen). * [Kontrollstrukturen](/frontend/referenz/kontrollstrukturen) * [Loops](/frontend/referenz/loops) * [Modifiers](/frontend/referenz/modifiers) — Diese Seite beschreibt die Grundlagen und Schreibweise von Modifiers. Modifiers (auch Filter genannt) werden verwendet, um Werte im Template direkt bei der Ausgabe oder Weiterverarbeitung zu verändern, zu formatieren oder zu prüfen – zum Beispiel Texte anpassen, Zahlen runden oder Listen umwandeln. * [Operatoren](/frontend/referenz/operatoren) * [Module](/frontend/referenz/module) — Module sind von WEBSALE vorgegebene, global verfügbare Module (z. B. \$wsAccount). Sie stellen Variablen (Eigenschaften) und Methoden bereit. In der Entwicklung werden sie teilweise auch als View-Module bezeichnet, da sie primär für die Ausgabe (Leseseite) verwendet werden. * [Variablen](/frontend/referenz/variablen) # Aktionen - Übersicht Source: https://dokumentation.websale.de/frontend/referenz/aktionen Übersicht aller Aktionen der Template-Sprache: Eingaben des Nutzers für Warenkorb, Login, Registrierung und mehr verarbeiten und Ergebnisse auswerten. Aktionen sind das Bindeglied zwischen dem, was ein Benutzer im Shop macht, und dem, was der Shop daraufhin ausführt. Ob ein Kunde ein Produkt in den Warenkorb legt, sich registriert oder einloggt - hinter jedem dieser Vorgänge steckt eine Aktion. Aktionen nehmen die Eingaben des Benutzers entgegen, verarbeiten sie im Hintergrund und geben dem Frontend zurück, ob alles geklappt hat oder ein Fehler aufgetreten ist. *** ## Grundprinzip Der Shop stellt eine Reihe vordefinierter Aktionen bereit. Diese sind vom System vorgegeben und können nicht frei benannt werden. Jede Aktionen hat einen festen Namen, zum Beispiel `BasketItemAdd` (Produkt in den Warenkorb legen), `Login` (Benutzer einloggen) oder `AccountRegister` (neues Konto anlegen). Aktionen können auf drei Arten ausgeführt werden: * Über ein Formular - der häufigste Fall. Der Benutzer füllt ein Formular aus und sendet es ab. * Über einen Link - für Aktionen ohne Benutzereingaben, zum Beispiel das Ausloggen. * Per AJAX - wenn die Seite nach der Ausführung nicht neu geladen werden soll. Unabhängig davon, wie eine Aktion ausgeführt wird, läuft im Hintergrund immer derselbe Prozess ab: Der Shop empfängt die Anfrage, verarbeitet sie und gibt zurück, ob die Aktion erfolgreich war oder ein Fehler aufgetreten ist. Einige Aktionen Verhalten sich abweichend und geben statt einer neuen Seite direkt Daten zurück, zum Beispiel als JSON im Rahmen des Checkouts. Dieses abweichende Verhalten ist bei den betreffenden Aktionen jeweils dokumentiert. *** ## Aktionen vorbereiten Bevor eine Aktion in einem Template genutzt werden kann, muss ein sogenanntes Aktionsobjekt erstellt werden. Man kann es sich wie einen Behälter vorstellen, der alles enthält, was für die Ausführung der Aktion benötigt wird und nach dem Absenden auch die Rückmeldung des Shops enthält. Das Aktionsobjekt wird mit [\$wsActions.create()](/frontend/referenz/module/wsactions#%24wsactions-create) erstellt, wobei der Name der gewünschten Aktion übergeben wird: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myAction = $wsActions.create("BasketItemAdd") }} ``` Optional kann hier bereits die Zielseite, auf die nach erfolgreicher Ausführung der Aktion weitergeleitet wird, mitgegeben werden: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myAction = $wsActions.create("BasketItemAdd", target=$wsViews.viewUrl('basket.htm')) }} ``` Das Objekt löst dabei noch nicht aus, es bereitet lediglich die Aktion vor. Die Aktion selbst wird erst ausgeführt, wenn der Benutzer das Formular absendet, auf einen Link klickt oder eine AJAX-Anfrage abgesendet wird. Nach der Ausführung befüllt der Shop das Aktionsobjekt automatisch mit Rückmeldungen. Im Template kann dann über die Variable `$myAction` darauf zugegriffen werden, zum Beispiel mit `$myAction.success` oder `$myAction.errors`. Eine vollständige Beschreibung aller verfügbaren Eigenschaften findet sich in der [\$wsActions Modulreferenz](/frontend/referenz/module/wsactions). | **Eigenschaft** | **Beschreibung** | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `$action.id` | Die ID der Aktion, die im Formular benötigt wird, damit der Shop weiß, was ausgeführt werden soll. | | `$action.csrf` | Ein Sicherheits-Token, das jede Anfrage absichert (mehr dazu [hier](#3-2-1-csrf-schutz)). | | `$action.success` | Ist `true`, wenn die Aktion erfolgreich ausgeführt wurde. | | `$action.error` | Ist `true`, wenn ein Fehler aufgetreten ist. | | `$action.errors` | Eine Liste aller aufgetretenen Fehler mit Fehlercode, betroffenem Feld und optionalem Detail. | | `$action.params` | Die zuletzt eingegebenen Werte. Nützlich, um ein Formular bei einem Fehler vorausgefüllt anzuzeigen, damit der Benutzer nicht alles neu eingeben muss. | *** ## Aktionen ausführen ### Ausführung über Formulare Der häufigste Weg, eine Aktion auszuführen, ist ein HTML-Formular. Das vorbereitete Aktionsobjekt wird in das Formular eingebunden und die Aktion wird ausgeführt, sobald der Benutzer das Formular absendet. Das Formular wird immer an die URL der aktuellen Seite gesendet, damit der Shop nach der Ausführung dieselbe Seite neu aufbauen und die Rückmeldung anzeigen kann: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
``` Jedes Formular, das eine Aktion ausführt, benötigt drei Pflichtfelder: | **Feld** | **Wert** | **Beschreibung** | | ---------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `wsact` | `{{= $action.id }}` | Teilt dem Shop mit, welche Aktion ausgeführt werden soll. | | `wscsrf` | `{{= $action.csrf }}` | Ein Sicherheits-Token zum Schutz vor unerlaubten Zugriffen (siehe LINK HIER EINFÜGEN). | | `wstarget` | `z.B. {{= $wsViews.viewUrl('basket.htm') }}` | Die Seite, auf die der Benutzer nach erfolgreicher Ausführung weitergeleitet wird. Die Weiterleitung verhindert außerdem, dass ein Seiten-Reload das Formular erneut absendet. | Zusätzlich zu den Pflichtfeldern enthält das Formular die aktionsspezifischen Felder. Welche das sind, ist in der jeweiligen Aktionsdokumentation beschrieben. Das folgende Beispiel zeigt ein vollständiges Formular zum Hinzufügen eines Produkts in den Warenkorb: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myAction = $wsActions.create("BasketItemAdd") }}
``` ### Tags - mehrere Formulare derselben Aktionsart unterscheiden Wenn auf einer Seite mehrere Formulare derselben Aktionsart vorkommen, zum Beispiel ein “In den Warenkorb”-Button in jeder Produktbox einer Kategorieseite, teilen sich alle diese Formulare standardmäßig dieselben Rückmeldungen. Das bedeutet: Tritt bei einem Produkt ein Fehler auf, würden alle Formulare auf der Seite diesen Fehler anzeigen. Mit einem Tag lässt sich jede Aktion eindeutig unterscheiden. Als Tag eignet sich zum Beispiel die Produkt-ID: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $action = $wsActions.create("BasketItemAdd", tag=$product.id) }} ``` Der Shop erzeugt daraus eine eindeutige ID im Format `BasketItemAdd:42` (wobei `42` in diesem Beispiel die Produkt-ID wäre). Dadurch erhält jedes Produkt ein eigenes Aktionsobjekt und Fehler erscheinen nur beim betreffenden Formular. Bei einigen Aktionen, insbesondere im Checkout, wird der Tag genutzt, um den Adresstyp direkt im Aktionsnamen festzulegen: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $commitBillAction = $wsActions.create("CheckoutCommitDraftAddress:bill") }} {{ var $commitShippingAction = $wsActions.create("CheckoutCommitDraftAddress:shipping") }} ``` ### Aktionen absichern Aktionen können auf zwei Arten gegen unerlaubte Zugriffe geschützt werden - durch einen CSRF-Token, der bei jeder Aktion Pflicht ist und optional durch ein Captcha. ### CSRF-Schutz CSRF (`Cross-Site Request Forgery`) bezeichnet einen Angriff, bei dem eine externe Website im Namen eines eingeloggten Benutzers unbemerkt Anfragen an den Shop sendet, zum Beispiel um eine Bestellung auszulösen oder Kontodaten zu ändern. Der CSRF-Schutz verhindert, dass solche Anfragen vom Shop akzeptiert werden. Dazu wird für jede Benutzersitzung ein einmaliger CSRF-Token erzeugt. Weil der Token an die aktuelle Sitzung gebunden ist, kann eine fremde Website ihn nicht kennen und die Aktion damit nicht unbemerkt auslösen. Der Token steht direkt am Aktionsobjekt zur Verfügung und wird so eingebunden: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` ### Captcha-Schutz Für bestimmte Aktionen, zum Beispiel die Registrierung oder ein Kontaktformular, kann zusätzlich ein Captcha aktiviert werden. Ein Captcha ist eine Sicherheitsabfrage, die sicherstellt, dass das Formular von einem echten Menschen ausgefüllt wird und nicht von einem automatisierten Bot. Ist der Captcha-Schutz für eine Aktion aktiv, wird die Aktion nur ausgeführt, wenn der Benutzer das Captcha erfolgreich gelöst hat. Schlägt die Prüfung fehl, wird die Aktion nicht ausgeführt. Damit der Schutz greift, sind zwei Voraussetzungen nötig: 1. Die Aktion muss in der [Shop-Konfiguration](/konfiguration/security-sicherheitsregeln) unter `security.actionGuard` für den Captcha-Schutz eingetragen sein. 2. Das Captcha-Widget muss im Template des zugehörigen Formulars eingebunden sein. Mehr dazu [hier](https://websale.atlassian.net/wiki/x/AwAhdw). Wird eine Aktion über einen Bestätigungslink per E-Mail ausgeführt (Opt-In-Link), findet keine Captcha-Prüfung statt. In diesem Fall gilt der Link selbst als Nachweis, dass ein Mensch gehandelt hat. ### Ausführung über Links Aktionen ohne Benutzereingaben, zum Beispiel das Ausloggen oder das Entfernen eines Artikels aus dem Warenkorb, können über einen Link ausgelöst werden, ohne das ein Formular nötig ist. Dazu wird mit [\$wsActions.url()](/frontend/referenz/module/wsactions#\$wsactions-url) eine URL erzeugt. Die Methode erwartet drei Angaben: den Aktionsnamen, die Zielseite nach der Ausführung und optionale Parameter als Liste. Sind keine optionalen Parameter nötig, wird eine leere Liste `{}` übergeben: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Ausloggen ``` ### Ausführung per AJAX Standardmäßig wird nach dem Absenden eines Formulars die gesamte Seite neu geladen. Manchmal ist das aber nicht gewünscht, zum Beispiel wenn nur ein kleiner Bereich der Seite aktualisiert werden soll, ohne das der Benutzer einen sichtbaren Neuladevorgang erlebt. In solchen Fällen kann die Aktion per AJAX ausgeführt werden. Dabei werden die Daten im Hintergrund an den Shop geschickt und die Antwort (Erfolg oder Fehler) direkt per JavaScript verarbeitet, ohne die Seite neu zu laden. CSRF-Schutz ist dabei genauso erforderlich wie bei Formularen, der Token ist über [\$wsActions.csrfToken](/frontend/referenz/module/wsactions#\$wsactions-current-csrf) abrufbar. Ein typisches Anwendungsbeispiel:\ Der Benutzer legt ein Produkt in den Warenkorb und nur der Warenkorb-Zähler im Header aktualisiert sich, der Rest der Seite bleibt unverändert. ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} $.post("{{= $wsViews.viewUrl('ajax/actionResponse.json') }}", { "wscsrf": "{{= $wsActions.csrfToken }}", "wsact": "BasketItemAdd", "productId": "12345", "quantity": 2 }, function(data) { if (data.success) { // Aktion erfolgreich – z.B. Warenkorb-Zähler im Header aktualisieren } else { // Fehler anzeigen console.log(data.errors); } }); ``` ### Mehrere Aktionen gleichzeitig ausführen Manchmal sollen mit einem einzigen Klick auf “Absenden” mehrere Aktionen nacheinander ausgeführt werden. Ein typisches Beispiel ist der letzte Schritt im Checkout, bei dem die Rechnungsadresse und die Lieferadresse bestätigt und die Bestellung abgeschlossen werden. Dafür wird statt des normalen `wsact`-Feldes das Feld `wsmultiact` verwendet, und zwar einmal pro Aktion. `wsact` und `wsmultiact` können nicht im selben Formular kombiniert werden. Die Aktionen werden in der Reihenfolge ausgeführt in der die `wsmultiact`-Felder im Formular aufgelistet sind.\\ #### Felder einer Aktion zuordnen Weil mehrere Aktionen im selben Formular Felder entgegennehmen, muss jedes Feld klar einer bestimmten Aktion zugeordnet werden. Das geschieht durch ein Präfix vor dem Feldnamen, getrennt durch `|`. Im Template sieht es so aus: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` Das bedeutet: Das Feld `addressType` mit dem Wert `bill` gehört zur Aktion `$commitBillAction`.\\ #### Fehler einer Aktion soll die nächste stoppen Standardmäßig werden alle Aktionen ausgeführt, auch wenn eine davon fehlschlägt. Soll eine fehlgeschlagene Aktion die nachfolgende abbrechen, kann der Parameter `wsmultiactabortonerror` auf `on` gesetzt werden: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` #### Fehler einer Aktion ignorieren `wsmultiactignoreerror` können einzelne Aktionen als unkritisch markiert werden. Schlägt eine so markierte Aktion fehl, wird das nicht als fataler Fehler behandelt. Der Parameter kann mehrfach angegeben werden, einmal pro Aktion: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` Einen Fehler zu ignorieren wirkt sich auf zwei Situationen aus: * **Weiterleitung trotz Fehler** \ Standardmäßig bleibt der Nutzer bei einem Fehler auf der aktuellen Seite und wird nicht auf die in `wstarget` angegebene Zielseite weitergeleitet. Ist die fehlgeschlagene Aktion über `wsmultiactignoreerror` markiert, findet die Weiterleitung dennoch statt. * **Folgeaktionen laufen weiter** \ Ist zusätzlich `wsmultiactabortonerror=on` gesetzt, würde ein Fehler normalerweise alle nachfolgenden Aktionen abbrechen. Aktionen, die über `wsmultiactignoreerror` markiert sind, lösen diesen Abbruch nicht aus - die Ausführung wird fortgesetzt. **Beispiel: Checkout-Abschluss**\ Das folgende Beispiel zeigt den letzten Schritt eines Checkouts. Mit einem Klick auf “Jetzt bestellen” werden drei Aktionen nacheinander ausgeführt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $commitBillAction = $wsActions.create("CheckoutCommitDraftAddress:bill") }} {{ var $commitShippingAction = $wsActions.create("CheckoutCommitDraftAddress:shipping") }} {{ var $checkoutConfirm = $wsActions.create("CheckoutConfirm") }}
``` Ausführungsreihenfolge des Beispiels: 1. `CheckoutCommitDraftAddress:bill` - Rechnungsadresse übernehmen 2. `CheckoutCommitDraftAddress:shipping`- Lieferadresse übernehmen 3. `CheckoutConfirm` - Bestellung abschließen ### Ergebnis der Ausführung #### Erfolg War die Aktion erfolgreich, ist `$myAction.success` gleich `true`. In diesem Fall kann eine Erfolgsmeldung angezeigt oder der Benutzer über `wstarget` auf eine andere Seite weitergeleitet werden. #### Fehler Schlägt die Aktion fehl, zum Beispiel weil ein Pflichtfeld fehlt oder eine E-Mail-Adresse ungültig ist, ist `$myAction.error` gleich `true`. Die Fehlermeldungen sollten im Template ausgegeben werden, damit der Benutzer weiß, was korrigiert werden muss: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $myAction.error }}
Bitte korrigiere folgende Angaben:
    {{ foreach $error in $myAction.errors }} {{ if $error.text }}
  • {{= $error.text }} ({{= $error.field }}){{ if $error.subCode }} – {{= $error.subCode }}{{ /if }}
  • {{ else }}
  • {{= $error.code }} ({{= $error.field }}){{ if $error.subCode }} – {{= $error.subCode }}{{ /if }}
  • {{ /if }} {{ /foreach }}
{{ /if }} ``` Welche Fehlercodes eine bestimmte Aktion zurückgeben kann, ist in der jeweiligen Aktionsdokumentation ausgeführt. Eine Erklärung aller Fehlereigenschaften findet sich in der [\$wsActions Modulreferenz](/frontend/referenz/module/wsactions). ### Weiterleitung Nach einer erfolgreich ausgeführten Aktion kann der Benutzer auf eine Zielseite weitergeleitet werden. Das verhindert außerdem, dass ein Seiten-Reload das Formular erneut absendet. Mehr dazu [hier](#2-aktionen-vorbereiten). *** ## Aktionsübersicht Eine vollständige Übersicht aller verfügbaren Aktionen findet sich in den jeweiligen Themenbereichen: * [Account](/frontend/referenz/aktionen/account) * [Basket](/frontend/referenz/aktionen/basket) * [Checkout](/frontend/referenz/aktionen/checkout) * [Consent](/frontend/referenz/aktionen/consent) * [DirectOrder](/frontend/referenz/aktionen/directorder) * [Inquiry](/frontend/referenz/aktionen/inquiry) * [Inventory](/frontend/referenz/aktionen/inventory) * [Newsletter](/frontend/referenz/aktionen/newsletter) * [ProductRating](/frontend/referenz/aktionen/productrating) * [Session](/frontend/referenz/aktionen/session) * [Stores](/frontend/referenz/aktionen/stores) * [TestMode](/frontend/referenz/aktionen/testmode) * [Voucher](/frontend/referenz/aktionen/voucher) * [WatchList](/frontend/referenz/aktionen/watchlist) # Account Source: https://dokumentation.websale.de/frontend/referenz/aktionen/account Aktionen für Kundenkonten: Konten und Adressen anlegen, Anmeldedaten und Passwörter ändern sowie B2B-Mitarbeiterkonten und Berechtigungen verwalten. In diesem Abschnitt werden die verfügbaren Aktionen im Bereich Kundenkonto beschrieben. Mithilfe dieser Aktionen können Sie Kundenkonten anlegen und verwalten, Anmeldedaten und Passwörter ändern sowie Adressen pflegen. Im B2B-Bereich ist zudem die Verwaltung von Mitarbeiterkonten und Berechtigungsgruppen möglich. ## Grundkonzept **Abgrenzung der Möglichkeiten im Kundenkonto:** * Daten lesen (Adressen, Profil, Login-Status) - erfolgt nicht über Aktionen, sondern über das Modul [\$wsAccount](/frontend/referenz/module/wsAccount). * **Strukturelle Einstellungen** - (Adressfelder, Kundendatenfelder, B2B-Konfiguration) werden in der [Konfiguration](/konfiguration) festgelegt. * Diese Seite beschreibt ausschließlich die Aktionen, die Konto-, Adress- und Berechtigungsdaten ### Grundlagen: Aufbau einer Aktion Jede Aktion wird mit `$wsActions.create("")` erzeugt und in ein Formular eingebunden. Pflichtfelder jedes Formulars sind `wsact` (ID der Aktion) und `wscsrf` (CSRF-Token). Details siehe [Aktionen - Übersicht](/frontend/referenz/aktionen). ### Adressen: Typen, Standard und Sichtbarkeit Adressen haben einen Typ (`bill` = Rechnungsadresse, `delivery` = Lieferadresse). Die erste Adresse eines Typs wird automatisch zur Hauptadresse dieses Typs. Über `SetMainAddress`, `SetDefaultBillAddress` und `SetDefaultDeliveryAddress` lassen sich Standardadressen festlegen, die im Checkout vorausgewählt werden. Im B2B-Kontext besitzt jede Adresse zusätzlich eine Sichtbarkeit: privat (nur für ein Mitarbeiterkonto) oder firmenweit freigegeben. Welcher Wert beim Anlegen vorausgewählt ist, steuert `defaultAddressVisibility` (siehe `UpdateSubAccount`). Wem eine Adresse gehört, steuert das Feld `addressOwnerMemberId` (siehe `AddressCreate`). ### B2B: Mitarbeiterkonten & Berechtigungsgruppen Diese Funktionen stehen ausschließlich für Firmenkonten im B2B-Bereich zur Verfügung; alle zugehörigen Aktionen erfordern Admin-Rechte. Eine Berechtigungsgruppe bündelt Rechte und Einschränkungen (z. B. erlaubte Zahlungsarten, Budgetgrenzen, gesperrte Seiten). Der typische Ablauf: 1. Gruppe anlegen → `CreatePrivilegeGroup` 2. Rechte/Einschränkungen der Gruppe setzen → `UpdatePrivileges` 3. Gruppe einem Mitarbeiterkonto zuweisen → `UpdateSubAccount` (`privilegeGroupId`) Mitarbeiterkonten selbst werden über `SubAccountCreate`, `UpdateSubAccount` und `SubAccountDelete` verwaltet. Die in der Gruppe gesetzten Budgetgrenzen werden im Frontend am Mitarbeiterkonto schreibgeschützt über [\$wsAccount.paymentLimit](/frontend/referenz/module/wsAccount) und `$wsAccount.paymentLimitPerOrder` gelesen. *** ## Aktionen im Überblick **Konto** | **Aktion** | **Beschreibung** | | ---------------------- | --------------------------------------------------------------- | | `AccountRegister` | Erstellt ein neues Kundenkonto. | | `AccountActivate` | Aktiviert ein bestehendes Kundenkonto über eine E-Mail-Adresse. | | `AccountActivateOptIn` | Aktiviert ein bestehendes Kundenkonto per Opt-In-Token. | | `EmailVerify` | Verifiziert eine E-Mail-Adresse per Double-Opt-In. | | `AccountDelete` | Löscht den Account des eingeloggten Benutzers. | | `AccountDeleteOptIn` | Bestätigt die Löschung eines Kundenkontos per Opt-In-Token. | **Anmeldung & Passwort** | **Aktion** | **Beschreibung** | | ----------------------- | ------------------------------------------------------------------- | | `Login` | Meldet einen Benutzer an. | | `Logout` | Meldet einen eingeloggten Benutzer ab. | | `UnlockLogin` | Entsperrt einen gesperrten Login-Zugang. | | `PasswordForgotten` | Sendet eine Passwort-vergessen-E-Mail. | | `ResetPassword` | Setzt das Passwort eines Benutzerkontos neu. | | `CheckPasswordStrength` | Prüft die Stärke eines eingegebenen Passworts in Echtzeit per AJAX. | **Konto- & Kontaktdaten** | **Aktion** | **Beschreibung** | | -------------------------- | ----------------------------------------------------------- | | `EmailUpdate` | Ändert die hinterlegte E-Mail-Adresse eines Benutzerkontos. | | `EmailUpdateOptIn` | Bestätigt die Änderung der E-Mail-Adresse per Opt-In-Token. | | `accountDisplayNameUpdate` | Ändert den Anzeigenamen eines Kundenkontos. | | `AccountSetCustomerData` | Setzt oder aktualisiert benutzerdefinierte Kundendaten. | **Adressen** | **Aktion** | **Beschreibung** | | ------------------------------ | -------------------------------------------------------------- | | `AddressCreate` | Erstellt eine neue Adresse für den eingeloggten Benutzer. | | `AddressUpdate` | Bearbeitet eine bestehende Adresse des eingeloggten Benutzers. | | `AddressDelete` | Löscht eine Adresse des eingeloggten Benutzers. | | `SetMainAddress` | Legt eine Adresse als Hauptadresse fest. | | `SetDefaultBillAddress` | Legt eine Adresse als Standard-Rechnungsadresse fest. | | `SetDefaultDeliveryAddress` | Legt eine Adresse als Standard-Lieferadresse fest. | | `RemoveDefaultBillAddress` | Entfernt die gesetzte Standard-Rechnungsadresse. | | `RemoveDefaultDeliveryAddress` | Entfernt die gesetzte Standard-Lieferadresse. | **Kreditkarten** | **Aktion** | **Beschreibung** | | ------------------ | --------------------------------------------------------- | | `CreditCardDelete` | Löscht eine gespeicherte Kreditkarte aus dem Kundenkonto. | **Gastkonto** | **Aktion** | **Beschreibung** | | --------------------- | ------------------------------------------------------------------------------------------ | | `GuestRegister` | Erstellt aus einem Gast-Checkout ein vollwertiges Kundenkonto (E-Mail aus Checkout-Daten). | | `SaveGuestDataToUser` | Erstellt aus einem Gast-Checkout ein vollwertiges Kundenkonto. | **B2B – Mitarbeiterkonten** (Admin-Rechte erforderlich) | **Aktion** | **Beschreibung** | | ------------------ | ------------------------------------------------------------------------------------------------ | | `SubAccountCreate` | Legt ein neues Mitarbeiterkonto an und sendet eine E-Mail mit dem Link zum Setzen des Passworts. | | `UpdateSubAccount` | Aktualisiert die Einstellungen eines Mitarbeiterkontos. | | `SubAccountDelete` | Löscht ein bestehendes Mitarbeiterkonto. | | `AcceptInvitation` | Nimmt eine Einladung zu einem Firmenkonto per Double-Opt-In an. | **B2B – Berechtigungsgruppen** (Admin-Rechte erforderlich) | **Aktion** | **Beschreibung** | | ---------------------- | ---------------------------------------------------------------------------- | | `CreatePrivilegeGroup` | Legt eine neue Berechtigungsgruppe an. | | `UpdatePrivileges` | Erstellt oder aktualisiert eine Berechtigungsgruppe mit definierten Rechten. | | `DeletePrivilegeGroup` | Löscht eine bestehende Berechtigungsgruppe. | *** ## Konto-Lebenszyklus ### AccountRegister Mit dieser Aktion wird ein neues Kundenkonto angelegt. Der Benutzer gibt dabei seine E-Mail-Adresse sowie ein Passwort an. **Anwendungsbeispiel**\ Nutzbar auf einer Registrierungsseite, auf der neue Kunden ein Konto erstellen können, um z.B. ihre Bestellhistorie einzusehen oder Adressen zu verwalten. **Parameter** | **Name** | **Beschreibung** | | ---------------- | -------------------------------------------------------------------- | | `email` | Identifier des Benutzer-Accounts (standardmäßig die E-Mail-Adresse). | | `password` | Passwort des Benutzer-Accounts. | | `passwordRepeat` | Erneute Eingabe des Passworts - muss mit `password` übereinstimmen. | **Fehlercodes** | **Code** | **Beschreibung** | | ---------------------- | --------------------------------------------------------------- | | `missingId` | Parameter `id` ist leer. | | `missingPassword` | Parameter `password` ist leer. | | `passwordMismatch` | Parameter `password` und `passwordRepeat` sind nicht identisch. | | `emailCheckFailed` | Parameter `id` enthält eine ungültige E-Mail-Adresse. | | `passwordCheckFailed` | Passwort erfüllt nicht die erforderlichen Richtlinien. | | `accountAlreadyExists` | Es existiert bereits ein Account mit der angegebenen `id`. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) **Beispiel** das zeigt, wie die Aktion erstellt und in ein Formular eingebunden wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cActionAccountRegister = $wsActions.create("AccountRegister") }}
``` *** ### AccountActivate Mit dieser Aktion wird ein bestehendes Kundenkonto aktiviert. Die Aktion wird typischerweise über ein Formular ausgelöst. **Anwendungsbeispiel**\ Nutzbar auf der Bestätigungsseite, auf der der Kunde seine E-Mail-Adresse eingibt, um sein Konto zu aktivieren. **Parameter** | **Name** | **Beschreibung** | | -------- | -------------------------------------------------------------------- | | `id` | Identifier des Benutzer-Accounts (standardmäßig die E-Mail-Adresse). | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ---------------------- | ------------------------------------------------------------------ | | `missingId` | Parameter `id` ist leer. | | `emailCheckFailed` | Parameter `id`enthält eine ungültige E-Mail-Adresse. | | `accountAlreadyExists` | Es existiert bereits ein aktiver Account mit der angegebenen `id`. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.isAccountVerified](/frontend/referenz/module/wsAccount#%24wsaccount-isaccountverified) **Beispiel** das zeigt, wie die Aktion erstellt und in ein Formular eingebunden wird, über das der Kunde seinen Account mit seiner E-Mail-Adresse aktiviert. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cActionAccountActivate = $wsActions.create("AccountActivate") }}
``` *** ### AccountActivateOptIn Mit dieser Aktion wird ein bestehendes Kundenkonto per Opt-In-Token aktiviert. Der Token wird dabei über einen Link in einer Bestätigungs-E-Mail an den Benutzer übermittelt. **Anwendungsbeispiel**\ Nutzbar auf der Bestätigungsseite, auf die der Kunde nach Klick auf den Opt-In-Link in der Registrierungs-E-Mail weitergeleitet wird. **Fehlercodes** | **Fehlercode** | **Beschreibung** | | -------------- | ---------------------------------------------- | | `unauthorized` | Es wurde kein gültiger Opt-In-Token übergeben. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.isAccountVerified](/frontend/referenz/module/wsAccount#%24wsaccount-isaccountverified) **Beispiel** das zeigt, wie nach erfolgreicher Ausführung der Aktion eine Bestätigungsmeldung angezeigt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsActions.current.name == "AccountActivateOptIn" and $wsActions.current.success }}
Account wurde aktiviert.
{{ /if }} ``` *** ### EmailVerify Mit dieser Aktion wird eine E-Mail-Adresse per Double-Opt-In verifiziert. Nach der Registrierung erhält der Kunde eine Bestätigungs-E-Mail; durch Klick auf den enthaltenen Link wird diese Aktion auf der Shop-Seite ausgeführt. **Anwendungsbeispiel**\ Nutzbar auf der Bestätigungsseite, auf die der Kunde nach Klick auf den Verifizierungslink in der Registrierungs-E-Mail weitergeleitet wird. **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | -------------------------------------------- | | `actionNotAllowed` | Kein gültiger Double-Opt-In-Token vorhanden. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) **Beispiel** das zeigt, wie nach erfolgreichem Klick auf den Bestätigungslink eine Erfolgsmeldung ausgegeben wird und bei einem ungültigen Token ein entsprechender Hinweis erscheint. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsActions.current.name == "EmailVerify" }} {{ if $wsActions.current.success }}
E-Mail-Adresse wurde verifiziert.
{{ else }}
E-Mail-Adresse konnte nicht verifiziert werden.
{{ /if }} {{ /if }} ``` *** ### AccountDelete Mit dieser Aktion wird der Account des aktuell eingeloggten Benutzers unwiderruflich gelöscht. **Anwendungsbeispiel**\ Nutzbar auf einer Account-Verwaltungsseite, auf der eingeloggte Kunden ihr Konto auf Wunsch selbst löschen können. **Fehlercodes** | **Code** | **Beschreibung** | | --------------- | ---------------------------------- | | **notLoggedIn** | Der Benutzer ist nicht eingeloggt. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) **Beispiel** das zeigt, wie die Aktion erstellt wird und über einen Bestätigungs-Button ausgelöst wird. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cActionAccountDelete = $wsActions.create("AccountDelete") }}
``` *** ### AccountDeleteOptIn Mit dieser Aktion wird die Löschung eines Kundenkontos per Opt-In-Token bestätigt. Der Token wird über einen Link in einer Bestätigungs-E-Mail an den Benutzer übermittelt. **Anwendungsbeispiel**\ Nutzbar auf der Bestätigungsseite, auf die der Kunde nach Klick auf den Opt-In-Link in der Löschungs-E-Mail weitergeleitet wird. **Fehlercodes** | **Fehlercode** | **Beschreibung** | | -------------- | ---------------------------------------------- | | `unauthorized` | Es wurde kein gültiger Opt-In-Token übergeben. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) **Beispiel** das zeigt, wie nach erfolgreicher Ausführung der Aktion eine Bestätigungsmeldung angezeigt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsActions.current.name == "AccountDeleteOptIn" and $wsActions.current.success }}
Account wurde gelöscht.
{{ /if }} ``` *** ## Anmeldung & Passwort ### Login Mit dieser Aktion wird ein Benutzer mit seinen Zugangsdaten angemeldet. **Anwendungsbeispiel**\ Nutzbar auf der Login-Seite, auf der Kunden sich mit E-Mail-Adresse und Passwort in ihr Konto einloggen können. **Parameter** | **Name** | **Beschreibung** | | ---------- | -------------------------------------------------------------------- | | `id` | Identifier des Benutzer-Accounts (standardmäßig die E-Mail-Adresse). | | `password` | Passwort des Benutzer-Accounts. | **Fehlercodes** | **Code** | **Beschreibung** | | -------------------- | ------------------------------------------------------------------ | | `missingId` | Parameter `id` ist leer. | | `missingPassword` | Parameter `password` ist leer. | | `emailCheckFailed` | Parameter `id` enthält eine ungültige E-Mail-Adresse. | | `loginBlocked` | Zu viele ungültige Loginversuche. | | `invalidCredentials` | Ungültiger Loginversuch - `id` oder `password` sind nicht korrekt. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) **Beispiel** das ein Login-Formular mit E-Mail und Passwort sowie einer allgemeinen Fehlerausgabe bei ungültigen Angaben erstellt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cActionLogin = $wsActions.create("Login") }}
{{ if $cActionLogin.error }}
Fehler aufgetreten
{{ /if }}
``` *** ### Logout Mit dieser Aktion wird ein eingeloggter Benutzer abgemeldet. **Anwendungsbeispiel**\ Nutzbar als Logout-Button im Header oder auf der Account-Übersichtsseite. **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) **Beispiel** das zeigt, wie die Aktion über einen einfachen Link ausgelöst wird, der den Benutzer nach dem Logout auf eine definierte Seite weiterleitet. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Ausloggen ``` *** ### UnlockLogin Mit dieser Aktion wird ein Login-Zugang entsperrt, der aufgrund zu vieler fehlgeschlagener Anmeldeversuche gesperrt wurde. Die Aktion kann sowohl von einem eingeloggten Benutzer als auch über einen Opt-In-Token ausgeführt werden. **Anwendungsbeispiel**\ Nutzbar, wenn ein Kunde nach mehreren Fehleingaben aus seinem Konto ausgesperrt wurde und einen Entsperrlink per E-Mail erhalten hat. **Fehlercodes** | **Code** | **Beschreibung** | | -------------- | ------------------------------------------------------------------------------------- | | `unauthorized` | Der Benutzer ist nicht eingeloggt oder es wurde kein gültiger Opt-In-Token übergeben. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) * [\$wsAccount.isAccountVerified](/frontend/referenz/module/wsAccount#%24wsaccount-isaccountverified) **Beispiel** das zeigt, wie nach erfolgreicher Ausführung der Aktion eine Bestätigungsmeldung angezeigt wird. Die Aktion selbst wird typischerweise über einen Opt-In-Link in einer E-Mail ausgelöst und benötigt kein Formular. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsActions.current.name == "UnlockLogin" and $wsActions.current.success }}
Account wurde entsperrt
{{ /if }} ``` *** ### PasswordForgotten Mit dieser Aktion wird eine Passwort-vergessen-E-Mail an die angegebene E-Mail-Adresse gesendet. Die E-Mail enthält einen Opt-In-Link, der die Ausführung der Aktion `ResetPassword` erlaubt. **Anwendungsbeispiel**\ Nutzbar auf einer “Passwort vergessen”-Seite, auf der Kunden ihre E-Mail-Adresse eingeben, um einen Wiederherstellungslink zu erhalten. **Parameter** | **Name** | **Beschreibung** | | -------- | ------------------------------------------------------------------------ | | `email` | E-Mail-Adresse des Benutzerkontos, an die der Opt-In-Link gesendet wird. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------------ | ------------------------------------------------------------------ | | `missingEmail` | Parameter `email` ist leer. | | `emailCheckFailed` | Parameter `email` enthält keine gültige E-Mail-Adresse. | | `passwordRecoveryFailed` | Es existiert kein Benutzerkonto zu der angegebenen E-Mail-Adresse. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) **Beispiel,** das ein Formular erstellt, über das der Kunde seine E-Mail-Adresse eingibt und nach erfolgreicher Ausführung eine Bestätigung erhält. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cActionPasswordForgotten = $wsActions.create("PasswordForgotten") }}
{{ if $cActionPasswordForgotten.success }}
Passwort erfolgreich zurückgesetzt
{{ /if }}
``` *** ### ResetPassword Mit dieser Aktion wird das Passwort eines Benutzerkontos neu gesetzt. Nach erfolgreicher Ausführung wird der Benutzer automatisch ausgeloggt. Standardmäßig gilt die Aktion für den eingeloggten Benutzer - wird ein Opt-In-Token mitgesendet, gilt sie für den mit dem Token verknüpften Benutzer. **Anwendungsbeispiel**\ Nutzbar auf der Seite, auf die der Kunde über den Passwort-vergessen-Link weitergeleitet wird, um dort ein neues Passwort zu vergeben. **Parameter** | **Name** | **Beschreibung** | | ------------------- | ------------------------------------------------------------------------------------------------- | | `newPassword` | Das neue Passwort, das für das Benutzerkonto gesetzt werden soll. | | `newPasswordRepeat` | Wiederholung des neuen Passworts zur Vermeidung von Tippfehlern. | | `passwordAuth` | Bisheriges Passwort des Benutzerkontos. Nicht erforderlich, wenn ein Opt-In-Token verwendet wird. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | --------------------- | -------------------------------------------------------------------------- | | `notLoggedIn` | Weder ein Opt-In-Token noch eine eingeloggte Session ist vorhanden. | | `missingPassword` | Parameter `newPassword` ist leer. | | `passwordMismatch` | Parameter `newPassword`und `newPasswordRepeat`sind nicht identisch. | | `missingPasswordAuth` | Parameter `passwordAuth` ist leer. Tritt nur ohne Opt-In-Token auf. | | `failedPasswordAuth` | Parameter `passwordAuth` stimmt nicht mit dem bisherigen Passwort überein. | | `passwordCheckFailed` | `newPassword` entspricht nicht den Passwortregeln. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) * [\$wsAccount.isPasswordResetRequired](/frontend/referenz/module/wsAccount#%24wsaccount-ispasswordresetrequired) **Beispiel** das zeigt, wie nach erfolgreichem Reset eine Bestätigung ausgegeben wird, bei einem gültigen Opt-In-Token das Formular zur Passwortvergabe erscheint und bei einem ungültigen Token ein Hinweis auf den abgelaufenen Link angezeigt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsOptIn.current.valid }} {{ var $cActionResetPassword = $wsActions.create("ResetPassword") }}
{{ else }}
Der Link ist abgelaufen.
{{ /if }} ``` *** ### CheckPasswordStrength Mit dieser Aktion wird die Stärke eines eingegebenen Passworts in Echtzeit geprüft. Die Aktion wird per AJAX im Hintergrund ausgeführt und gibt ein JSON-Objekt mit dem Bewertungsergebnis zurück. **Anwendungsbeispiel**\ Nutzbar auf Seiten mit Passwort-Eingabefeldern, z.B. auf der Registrierungsseite, um dem Kunden direktes Feedback zur Passwortstärke zu geben. **Parameter** | **Name** | **Beschreibung** | | ---------- | ------------------------- | | `password` | Das zu prüfende Passwort. | **Rückgabewerte** | **Wert** | **Beschreibung** | | -------- | --------------------------------------- | | `value` | Erreichte Punktzahl der Passwortstärke. | | `max` | Maximale Punktzahl der Passwortstärke. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) **Beispiel** das zeigt, wie die Passwortstärke bei Eingabe in Echtzeit geprüft und dem Benutzer visuell als schwach, mittel oder stark angezeigt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cActionCheckPasswordStrength = $wsActions.create("CheckPasswordStrength") }} ``` *** ## Konto- & Kontaktdaten ### EmailUpdate Mit dieser Aktion wird die hinterlegte E-Mail-Adresse eines Benutzerkontos geändert. **Anwendungsbeispiel**\ Nutzbar auf der Account-Verwaltungsseite, auf der eingeloggte Kunden ihre E-Mail-Adresse aktualisieren können. **Parameter** | **Name** | **Beschreibung** | | -------- | ---------------------------------------------------------------------- | | `email` | Neue E-Mail-Adresse, die für das Benutzerkonto hinterlegt werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ---------------------- | ------------------------------------------------------------------- | | `missingEmail` | Parameter `email` fehlt. | | `emailCheckFailed` | Parameter `email` enthält keine gültige E-Mail-Adresse. | | `accountAlreadyExists` | Es existiert bereits ein anderer Account mit dieser E-Mail-Adresse. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.email](/frontend/referenz/module/wsAccount#%24wsaccount-email) **Beispiel** das ein Formular zur Eingabe einer neuen E-Mail-Adresse bereitstellt und nach erfolgreicher Ausführung eine Bestätigung ausgibt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cActionEmailUpdate = $wsActions.create("EmailUpdate") }} {{ if $cActionEmailUpdate.success }}
E-Mail-Adresse erfolgreich aktualisiert.
{{ else }}
{{ /if }} ``` *** ### EmailUpdateOptIn Mit dieser Aktion wird die Änderung der E-Mail-Adresse per Opt-In-Token bestätigt. Der Token wird über einen Link in einer Bestätigungs-E-Mail an die neue E-Mail-Adresse übermittelt. **Anwendungsbeispiel**\ Nutzbar auf der Bestätigungsseite, auf die der Kunde nach Klick auf den Opt-In-Link in der Bestätigungs-E-Mail weitergeleitet wird. **Fehlercodes** | **Fehlercode** | **Beschreibung** | | -------------- | ---------------------------------------------- | | `unauthorized` | Es wurde kein gültiger Opt-In-Token übergeben. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) **Beispiel** das zeigt, wie bei einem gültigen Opt-In-Token ein Bestätigungsformular angezeigt wird, nach erfolgreicher Ausführung eine Erfolgsmeldung erscheint und bei einem abgelaufenen Token ein entsprechender Hinweis ausgegeben wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cActionEmailUpdateOptIn = $wsActions.create("EmailUpdateOptIn") }} {{ if $wsActions.current.success and $wsActions.current.name == "EmailUpdateOptIn" }}
E-Mail-Adresse wurde erfolgreich geändert.
{{ elseif $wsOptIn.current.valid }}
{{ else }}
Der Token ist abgelaufen.
{{ /if }} ``` *** ### accountDisplayNameUpdate Mit dieser Aktion wird der Anzeigename eines Kundenkontos geändert. **Anwendungsbeispiel**\ Nutzbar auf der Account-Verwaltungsseite, auf der eingeloggte Kunden ihren Anzeigenamen aktualisieren können. **Parameter** | **Name** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------- | | `displayName` | Der neue Anzeigename, der für das Benutzerkonto hinterlegt werden soll. | **Fehlercodes** | **Code** | **Beschreibung** | | -------------------- | ---------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `missingDisplayName` | Parameter `displayName` fehlt. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) **Beispiel** das zeigt, wie die Aktion erstellt und in ein Formular eingebunden wird, über das der Kunde seinen Anzeigenamen aktualisieren kann. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cActionAccountDisplayNameUpdate = $wsActions.create("accountDisplayNameUpdate") }}
``` *** ### AccountSetCustomerData Mit dieser Aktion werden benutzerdefinierte Kundendaten für das eingeloggte Benutzerkonto gesetzt oder aktualisiert. **Anwendungsbeispiel**\ Nutzbar auf der Account-Verwaltungsseite, auf der eingeloggte Kunden ihre persönlichen Daten wie z.B. Geburtsdatum oder Telefonnummer hinterlegen können. **Parameter** | **Name** | **Beschreibung** | | -------------------------- | ------------------------------------- | | `customerData.(fieldname)` | Die einzelnen Felder der Kundendaten. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------- | -------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `emptyCustomerData` | Es wurden keine Kundendatenfelder übergeben. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) **Beispiel** das zeigt, wie die Aktion erstellt und in ein Formular eingebunden wird, über das der Kunde seine persönlichen Daten aktualisieren kann. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cActionAccountSetCustomerData = $wsActions.create("AccountSetCustomerData") }}
``` *** ## Adressen ### AddressCreate Mit dieser Aktion wird eine neue Adresse für den eingeloggten Benutzer erstellt. **Anwendungsbeispiel**\ Nutzbar auf der Adressverwaltungsseite, auf der Kunden neue Liefer- oder Rechnungsadressen anlegen können. **Parameter** | **Name** | **Beschreibung** | | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `address.(fieldname)` | Die einzelnen Felder der Adresse, z.B. `address.firstName`, `address.street`etc. | | `type` | Art der Adresse: - `“bill”` - Rechnungsadresse - `“delivery”` - Lieferadresse Handelt es sich für das betreffende Kundenkonto um die erste Adresse seiner Art, wird sie automatisch als Hauptadresse für den jeweiligen Typ gesetzt. | | `address.addressOwnerMemberId` | *(B2B)* ID des Mitarbeiters, dem die Adresse gehört. Wird das Feld nicht übergeben oder auf `0` gesetzt, ist die Adresse eine firmenweite Adresse, die jeder Mitarbeiter sehen und nutzen kann. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt und kein Opt-In-Token vorhanden. | | `emptyAddress` | Es wurden keine Adressfelder übergeben. | | `addressCheckFailed` | Fehler in den Adressdaten. Wird über Sub-Codes konkretisiert: - `minlen` = zu wenig Zeichen - `maxlen` = zu viele Zeichen - `numeric` = ungültige Zeichen - `country` = Land nicht konfiguriert - `zip` = Postleitzahl fehlerhaft | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.addresses](/frontend/referenz/module/wsAccount#%24wsaccount-addresses) **Beispiel** das zeigt, wie eine neue Adresse über ein Formular mit einzelnen Adressfeldern angelegt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionAddressCreate = $wsActions.create("AddressCreate") }}
``` **Beispiel (B2B)** das zeigt, wie eine Lieferadresse angelegt wird, die nur einem bestimmten Mitarbeiter gehört. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionAddressCreate = $wsActions.create("AddressCreate") }}
``` *** ### AddressUpdate Mit dieser Aktion wird eine bestehende Adresse des eingeloggten Benutzers bearbeitet. **Anwendungsbeispiel**\ Nutzbar auf der Adressverwaltungsseite, wenn ein Kunde eine seiner gespeicherten Adressen aktualisieren möchte. **Parameter** | **Name** | **Beschreibung** | | --------------------- | ------------------------------------------------------------------------------ | | `addressId` | Die ID der Adresse, die bearbeitet werden soll. | | `address.(fieldname)` | Die einzelnen Felder der Adresse, die aktualisiert werden sollen. | | `type` | Art der Adresse: - `“bill”` - Rechnungsadresse - `“delivery”` - Lieferadresse | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | ---------------------------------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt und es ist kein Opt-In-Token vorhanden. | | `emptyAddress` | Es wurden keine Adressfelder übergeben. | | `invalidAddressId` | Ungültige `addressId` - die Adresse existiert nicht oder gehört nicht zu diesem Benutzerkonto. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.addresses](/frontend/referenz/module/wsAccount#%24wsaccount-addresses) * [\$wsAccount.loadAddress](/frontend/referenz/module/wsAccount#%24wsaccount-loadaddress) **Beispiel** das zeigt, wie eine bestehende Adresse anhand ihrer ID bearbeitet wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionAddressUpdate = $wsActions.create("AddressUpdate") }}
``` *** ### AddressDelete Mit dieser Aktion wird eine Adresse des eingeloggten Benutzers gelöscht. **Anwendungsbeispiel**\ Nutzbar auf der Adressverwaltungsseite, wenn ein Kunde eine nicht mehr benötigte Adresse entfernen möchte. **Parameter** | **Name** | **Beschreibung** | | ----------- | --------------------------------------------- | | `addressId` | Die ID der Adresse, die gelöscht werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | ---------------------------------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt und es ist kein Opt-In-Token vorhanden. | | `invalidAddressId` | Ungültige `addressId` - die Adresse existiert nicht oder gehört nicht zu diesem Benutzerkonto. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.addresses](/frontend/referenz/module/wsAccount#%24wsaccount-addresses) **Beispiel** das zeigt, wie eine Adresse über ihre ID gelöscht wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cActionAddressDelete = $wsActions.create("AddressDelete") }}
``` *** ### SetMainAddress Mit dieser Aktion wird eine gespeicherte Adresse als Hauptadresse festgelegt. Die Hauptadresse wird im Checkout automatisch vorausgewählt. **Anwendungsbeispiel**\ Nutzbar auf der Adressverwaltungsseite, damit Kunden ihre bevorzugte Adresse als Standard für zukünftige Bestellungen hinterlegen können. **Parameter** | **Name** | **Beschreibung** | | ----------- | ------------------------------------------------------------- | | `addressId` | Die ID der Adresse, die als Hauptadresse gesetzt werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | --------------------------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `missingAddressId` | Parameter `addressId` fehlt. | | `invalidAddressId` | Ungültige `addressId` - die Adresse existiert nicht oder gehört zu einem anderen Konto. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.addresses](/frontend/referenz/module/wsAccount#%24wsaccount-addresses) **Beispiel** das zeigt, wie eine Adresse per Button als Hauptadresse gesetzt wird, sofern sie es nicht bereits ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cActionSetMainAddress = $wsActions.create("SetMainAddress") }} {{ foreach $cAddress in $wsAccount.addresses }} {{ if $cAddress.id != $wsAccount.mainAddress.id }}
{{ /if }} {{ /foreach }} ``` *** ### SetDefaultBillAddress Mit dieser Aktion wird eine gespeicherte Adresse als Standard-Rechnungsadresse festgelegt. Die Standard-Rechnungsadresse wird im Checkout automatisch als Rechnungsadresse vorausgewählt. **Anwendungsbeispiel**\ Nutzbar auf der Adressverwaltungsseite, damit Kunden eine bevorzugte Rechnungsadresse als Standard für zukünftige Bestellungen hinterlegen können. **Parameter** | **Name** | **Beschreibung** | | ----------- | -------------------------------------------------------------------------- | | `addressId` | Die ID der Adresse, die als Standard-Rechnungsadresse gesetzt werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | --------------------------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `missingAddressId` | Parameter `addressId` fehlt. | | `invalidAddressId` | Ungültige `addressId` - die Adresse existiert nicht oder gehört zu einem anderen Konto. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.addresses](/frontend/referenz/module/wsAccount#%24wsaccount-addresses) * [\$wsAccount.defaultBillAddress](/frontend/referenz/module/wsAccount#%24wsaccount-defaultbilladdress) **Beispiel** das zeigt, wie eine Adresse per Button als Standard-Rechnungsadresse gesetzt wird, sofern sie es nicht bereits ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionSetDefaultBillAddress = $wsActions.create("SetDefaultBillAddress") }}
``` *** ### SetDefaultDeliveryAddress Mit dieser Aktion wird eine gespeicherte Adresse als Standard-Lieferadresse festgelegt. Die Standard-Lieferadresse wird im Checkout automatisch als Lieferadresse vorausgewählt. **Anwendungsbeispiel**\ Nutzbar auf der Adressverwaltungsseite, damit Kunden eine bevorzugte Lieferadresse als Standard für zukünftige Bestellungen hinterlegen können. **Parameter** | **Name** | **Beschreibung** | | ----------- | ----------------------------------------------------------------------- | | `addressId` | Die ID der Adresse, die als Standard-Lieferadresse gesetzt werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | --------------------------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `missingAddressId` | Parameter `addressId` fehlt. | | `invalidAddressId` | Ungültige `addressId` - die Adresse existiert nicht oder gehört zu einem anderen Konto. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.addresses](/frontend/referenz/module/wsAccount#%24wsaccount-addresses) * [\$wsAccount.defaultDeliveryAddress](/frontend/referenz/module/wsAccount#\$wsaccount-defaultdeliveryaddress) **Beispiel** das zeigt, wie eine Adresse per Button als Standard-Lieferadresse gesetzt wird, sofern sie es nicht bereits ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionSetDefaultDeliveryAddress = $wsActions.create("SetDefaultDeliveryAddress") }}
``` *** ### RemoveDefaultBillAddress Mit dieser Aktion wird die gesetzte Standard-Rechnungsadresse des eingeloggten Benutzers entfernt. **Anwendungsbeispiel**\ Nutzbar auf der Adressverwaltungsseite, wenn ein Kunde die Standard-Rechnungsadresse zurücksetzen möchte, sodass im Checkout keine Adresse mehr vorausgewählt ist. **Fehlercodes** | **Fehlercode** | **Beschreibung** | | -------------- | ---------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.addresses](/frontend/referenz/module/wsAccount#%24wsaccount-addresses) * [\$wsAccount.defaultBillAddress](/frontend/referenz/module/wsAccount#%24wsaccount-defaultbilladdress) **Beispiel** das zeigt, wie die Standard-Rechnungsadresse über einen Button entfernt wird, sofern eine gesetzt ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionRemoveDefaultBillAddress = $wsActions.create("RemoveDefaultBillAddress") }}
``` *** ### RemoveDefaultDeliveryAddress Mit dieser Aktion wird die gesetzte Standard-Lieferadresse des eingeloggten Benutzers entfernt. **Anwendungsbeispiel**\ Nutzbar auf der Adressverwaltungsseite, wenn ein Kunde die Standard-Lieferadresse zurücksetzen möchte, sodass im Checkout keine Adresse mehr vorausgewählt ist. **Fehlercodes** | **Fehlercode** | **Beschreibung** | | -------------- | ---------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.addresses](/frontend/referenz/module/wsAccount#%24wsaccount-addresses) * [\$wsAccount.defaultDeliveryAddress](/frontend/referenz/module/wsAccount#\$wsaccount-defaultdeliveryaddress) **Beispiel** das zeigt, wie die Standard-Lieferadresse über einen Button entfernt wird, sofern eine gesetzt ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionRemoveDefaultDeliveryAddress = $wsActions.create("RemoveDefaultDeliveryAddress") }}
``` *** ## Kreditkarten ### CreditCardDelete Mit dieser Aktion wird eine gespeicherte Kreditkarte aus dem Kundenkonto gelöscht. **Anwendungsbeispiel**\ Nutzbar auf der Kreditkartenverwaltungsseite, auf der eingeloggte Kunden ihre gespeicherten Kreditkarten einsehen und entfernen können. **Parameter** | **Name** | **Beschreibung** | | ------------ | ------------------------------------------------- | | `pseudoCCId` | Die ID der Kreditkarte, die gelöscht werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------- | --------------------------------------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `invalidPseudoCCId` | Ungültige `pseudoCCId` - die Kreditkarte existiert nicht oder gehört nicht zu diesem Benutzerkonto. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.pseudoCreditCards](/frontend/referenz/module/wsAccount#%24wsaccount-pseudocreditcards) **Beispiel** das zeigt, wie alle gespeicherten Kreditkarten aufgelistet werden und jede einzelne über einen Button gelöscht werden kann. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cCreditCards = $wsAccount.pseudoCreditCards }} {{ foreach $cCreditCard in $wsAccount.pseudoCreditCards }} {{ var $cActionCreditCardDelete = $wsActions.create("CreditCardDelete") }}
{{ /foreach }} ``` *** ## Gast → Konto ### GuestRegister Mit dieser Aktion wird aus einem Gast-Checkout ein vollwertiges Kundenkonto erstellt. Der Gast gibt dabei ein Passwort an, die E-Mail-Adresse wird automatisch aus den Checkout-Daten übernommen. **Anwendungsbeispiel**\ Nutzbar auf der Bestellbestätigungsseite nach einem Gast-Checkout, auf der nicht eingeloggte Kunden die Möglichkeit erhalten, sich direkt ein Konto anzulegen. **Parameter** | **Name** | **Beschreibung** | | ---------------- | ----------------------------------------------------------------------------------- | | `guestMail` | E-Mail-Adresse des Gast-Kontos, wird automatisch aus den Checkout-Daten übernommen. | | `password` | Neues Passwort für das Kundenkonto. | | `passwordRepeat` | Wiederholung des Passworts. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `passwordCheckFailed` | Passwort erfüllt nicht die erforderlichen Richtlinien. Wird über Sub-Codes konkretisiert: - `minlen` = zu wenig Zeichen - `maxlen` = zu viele Zeichen | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) * [\$wsAccount.email](/frontend/referenz/module/wsAccount#%24wsaccount-email) **Beispiel** das zeigt, wie nicht eingeloggten Kunden nach einem Gast-Checkout die Möglichkeit geboten wird, ein Kundenkonto anzulegen, inklusive Erfolgsausgabe. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if not $wsAccount.isLoggedIn }} {{ var $cGuestRegister = $wsActions.create("GuestRegister") }} {{ if $cGuestRegister.success }}
Es wurde ein Konto angelegt.
{{ /if }} {{ if not $cGuestRegister.success }}
{{ /if }} {{ /if }} ``` *** ### SaveGuestDataToUser Mit dieser Aktion wird aus den Daten eines Gast-Checkouts ein vollwertiges Kundenkonto erstellt. Der Gast gibt dabei ein Passwort an und erhält damit Zugang zu einem dauerhaften Konto. **Anwendungsbeispiel**\ Nutzbar auf der Bestellbestätigungsseite nach einem Gast-Checkout, um dem Kunden die Möglichkeit zu geben, sich direkt ein Konto anzulegen, ohne erneut alle Daten eingeben zu müssen. **Parameter** | **Name** | **Beschreibung** | | ---------------- | ----------------------------------- | | `id` | E-Mail-Adress des Gast-Kontos. | | `password` | Neues Passwort für das Kundenkonto. | | `passwordRepeat` | Wiederholung des Passworts. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | --------------------- | --------------------------------------------------------------- | | `nonGuestAccount` | Der Benutzer ist bereits in einem Kundenkonto eingeloggt. | | `missingId` | Parameter `id` fehlt. | | `missingPassword` | Parameter `password` fehlt. | | `passwordMismatch` | Parameter `password` und `passwordRepeat` sind nicht identisch. | | `passwordCheckFailed` | Passwortregel-Prüfung ist fehlgeschlagen. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.addresses](/frontend/referenz/module/wsAccount#%24wsaccount-addresses) * [\$wsAccount.isLoggedIn](/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) **Beispiel** das zeigt, wie ein Gast-Kunde nach dem Checkout ein dauerhaftes Konto anlegen kann, indem er nur ein Passwort vergeben muss. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cActionSaveGuestDataToUser = $wsActions.create("SaveGuestDataToUser") }}
``` *** ## B2B – Mitarbeiterkonten Alle Aktionen in diesem Abschnitt erfordern Admin-Rechte und stehen nur für Firmenkonten im B2B-Bereich zur Verfügung. Eine Einführung in das Zusammenspiel von Mitarbeiterkonten und Berechtigungsgruppen findet sich im Abschnitt [Konzepte](#konzepte). ### SubAccountCreate Mit dieser Aktion wird ein neues Mitarbeiterkonto angelegt. An die angegebene E-Mail-Adresse wird automatisch eine [E-Mail](https://dokumentation.websale.de/konfiguration/b2b-business-to-business-b2b#b2b-userinvitation-benutzereinladung) mit einem Link zum Setzen des Passworts gesendet. Für diese Aktion sind Admin-Rechte erforderlich. **Anwendungsbeispiel**\ Nutzbar auf der Account-Verwaltungsseite, auf der Administratoren neue Mitarbeiterkonten anlegen können. **Parameter** | **Name** | **Beschreibung** | | -------- | ------------------------------------------------------------------------------------------------------------------- | | `email` | E-Mail-Adresse des neuen Mitarbeiterkontos.
An diese Adresse wird der Link zum Setzen des Passworts gesendet. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ---------------------- | -------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `unauthorized` | Der Benutzer verfügt nicht über Admin-Rechte. | | `missingId` | Parameter `email` ist leer. | | `emailCheckFailed` | Parameter `email`enthält eine ungültige E-Mail-Adresse. | | `accountAlreadyExists` | Es existiert bereits ein Account mit der angegebenen E-Mail-Adresse. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) **Beispiel** das zeigt, wie die Aktion erstellt und in ein Formular eingebunden wird, über das ein neues Mitarbeiterkonto angelegt werden kann. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionSubAccountCreate = $wsActions.create("SubAccountCreate") }}
``` *** ### UpdateSubAccount Mit dieser Aktion werden die Einstellungen des bestehenden Mitarbeiterkontos aktualisiert. Eine Deaktivierung des eigenen Kontos oder das Entziehen der Admin-Rechte ist nicht möglich. Für diese Aktion sind Admin-Rechte erforderlich. **Anwendungsbeispiel**\ Nutzbar auf der Mitarbeiterverwaltungsseite, auf der Administratoren Rollen und weitere Einstellungen von Mitarbeiterkonten anpassen können. **Parameter** | Name | Beschreibung | | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `memberId` | Die ID des Mitarbeiterkontos, das aktualisiert werden soll. | | `displayName` | Anzeigename des Mitarbeiterkontos. | | `active` | Gibt an, ob sich das Mitarbeiterkonto anmelden darf (`true` / `false`).
Das eigene Konto kann nicht deaktiviert werden. | | `admin` | Gibt an, ob das Konto Admin-Rechte besitzt (`true` / `false`).
Dem eigenen Konto können keine Admin-Rechte entzogen werden. | | `privilegeGroupId` | ID der Berechtigungsgruppe, die dem Mitarbeiterkonto zugewiesen wird. | | `defaultAddressVisibility` | Legt fest, welche Sichtbarkeit beim Anlegen neuer Adressen standardmäßig vorausgewählt ist.
Mögliche Werte:
- `private` (nur für dieses Konto sichtbar)
- `shared` (firmenweit freigegeben) | | `allowedSubshops` | Legt fest, auf welche Subshops das Mitarbeiterkonto Zugriff hat.
Die [Subshop-IDs](https://dokumentation.websale.de/frontend/referenz/module/wssubshop#\$wssubshop-subshops) werden als Schlüssel eines JSON-Objekts übergeben, z.B. `{"shop1": true, "shop2": true}.` | **Fehlercodes** | Fehlercode | Beschreibung | | -------------------------- | ------------------------------------------------------------------------------------------------ | | notLoggedIn | Der Benutzer ist nicht eingeloggt. | | unauthorized | Der Benutzer verfügt nicht über Admin-Rechte. | | missingMemberId | Parameter `memberId` fehlt. | | invalidMemberId | Ungültige `memberId` - das Mitarbeiterkonto existiert nicht oder gehört nicht zu diesem Account. | | selfDeactivationNotAllowed | Das eigene Konto kann nicht deaktiviert werden. | | selfAdminRemovalNotallowed | Dem eigenen Konto können keine Admin-Rechte entzogen werden. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](https://dokumentation.websale.de/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](https://dokumentation.websale.de/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) * [\$wsSubshop.subshops](https://dokumentation.websale.de/frontend/referenz/module/wssubshop#\$wssubshop-subshops) **Beispiel** das zeigt, wie die Einstellungen eines Mitarbeiterkontos über ein Formular aktualisiert werden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionUpdateSubAccount = $wsActions.create("UpdateSubAccount") }}
``` *** ### SubAccountDelete Mit dieser Aktion wird ein bestehendes Mitarbeiterkonto gelöscht. Das eigene Konto sowie Konten mit Admin-Rechten können nicht gelöscht werden. Für diese Aktion sind Admin-Rechte erforderlich. **Anwendungsbeispiel**\ Nutzbar auf der Mitarbeiterverwaltungsseite, auf der Administratoren nicht mehr benötigte Mitarbeiterkonten entfernen können. **Parameter** | Name | Beschreibung | | ---------- | ------------------------------------------------------- | | `memberId` | Die ID des Mitarbeiterkontos, das gelöscht werden soll. | **Fehlercodes** | Fehlercode | Beschreibung | | -------------------- | ---------------------------------------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `unauthorized` | Der Benutzer verfügt nicht über Admin-Rechte. | | `missingMemberId` | Parameter `memberId `fehlt. | | `invalidMemberId` | Ungültige `memberId `- das Mitarbeiterkonto existiert nicht oder gehört nicht zu diesem Account. | | `deletionNotAllowed` | Das Konto darf nicht gelöscht werden, weil es sich um das eigene Konto oder ein Admin-Konto handelt. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](https://dokumentation.websale.de/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](https://dokumentation.websale.de/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) **Beispiel** das zeigt, wie ein Mitarbeiterkonto über seine ID gelöscht wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionSubAccountDelete = $wsActions.create("SubAccountDelete") }}
``` *** ### AcceptInvitation Mit dieser Aktion nimmt ein B2B-Firmenkunde eine Einladung per Double-Opt-In-Verfahren an. Der Token ist in einem Link enthalten, den der Kunde per E-Mail erhält. Nach erfolgreicher Verifizierung hat das Konto vollen Zugriff auf den Shop. **Anwendungsbeispiel**\ Nutzbar auf der Bestätigungsseite, auf die der eingeladene Kunde nach Klick auf den Einladungslink in der E-Mail weitergeleitet wird. **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | -------------------------------------------------------------------- | | `unauthorized` | Es wurde kein gültiger Opt-In-Token übergeben. | | `invalidAccountId` | Der Double-Opt-In-Token konnte keinem Kundenkonto zugeordnet werden. | | `actionNotAllowed` | Der Double-Opt-In-Token ist ungültig oder passt nicht zum Konto. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.isAccountVerified](/frontend/referenz/module/wsAccount#%24wsaccount-isaccountverified) **Beispiel** das zeigt, wie nach erfolgreicher Annahme der Einladung eine Bestätigungsmeldung angezeigt wird. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsActions.current.name == "AcceptInvitation" and $wsActions.current.success }}
Einladung wurde angenommen.
{{ /if }} ``` *** ## B2B – Berechtigungsgruppen Alle Aktionen in diesem Abschnitt erfordern Admin-Rechte und stehen nur für Firmenkonten im B2B-Bereich zur Verfügung. Zum Zusammenspiel mit Mitarbeiterkonten siehe Abschnitt [Konzepte](#konzepte). ### CreatePrivilegeGroup Mit dieser Aktion wird eine neue Berechtigungsgruppe erstellt. Für diese Aktion sind Admin-Rechte erforderlich. **Anwendungsbeispiel**\ Nutzbar auf der Berechtigungsverwaltungsseite, auf der Administratoren neue Gruppen mit definierten Rechten für Mitarbeiterkonten erstellen können. **Parameter** | Name | Beschreibung | | ------ | ----------------------------------- | | `name` | Name der neuen Berechtigungsgruppe. | **Fehlercodes** | Fehlercode | Beschreibung | | -------------- | --------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `unauthorized` | Der Benutzer verfügt nicht über Admin-Rechte. | | `missingName` | Parameter `name` fehlt oder ist leer. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](https://dokumentation.websale.de/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](https://dokumentation.websale.de/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) **Beispiel** das zeigt, wie eine neue Berechtigungsgruppe über ein Formular angelegt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionCreatePrivilegeGroup = $wsActions.create("CreatePrivilegeGroup") }}
``` *** ### UpdatePrivileges Mit dieser Aktion wird eine Berechtigungsgruppe aktualisiert. Für diese Aktion sind Admin-Rechte erforderlich. **Anwendungsbeispiel**\ Nutzbar auf der Berechtigungsverwaltungsseite, auf der Administratoren Rechte und Einschränkungen für Berechtigungsgruppen definieren können. **Parameter** | Name | Beschreibung | | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `privilegeId` | Die ID der Berechtigungsgruppe, die aktualisiert werden soll. | | `createMissing` | Gibt an, ob die Gruppe automatisch erstellt werden soll, falls sie nicht existiert.
Mögliche Werte:
- `yes` | | `type` | Art der Berechtigungsgruppe:
- `global` (shopweit)
- `account` (kontobezogen) | | `privileges` | JSON-Objekt mit den Berechtigungsfeldern.
Mögliche Felder:
- `allowedPaymentMethods` (JSON-Objekt mit erlaubten Zahlungsarten: Zahlarten-ID als Schlüssel, `"1"` als Wert schaltet die Zahlart frei, alle anderen Werte werden ignoriert)
- `paymentLimitPerOrder` (maximaler Bestellwert pro Bestellung)
- `paymentLimit` (globale Budgetgrenze über alle Bestellungen seit Limitsetzung)
- `blockedTemplates` (gesperrte Templates / Seiten der Gruppe)
- `blockedUrls` (gesperrte URLs der Gruppe)
- `editableFields` (bearbeitbare Felder der Gruppe)
- `groupName` (nur relevant bei `type = global`) | Die beiden Budgetgrenzen wirken zusammen: `paymentLimitPerOrder` begrenzt jede einzelne Bestellung, `paymentLimit` die kumulierte Ausgabensumme. Beide Werte werden im Frontend schreibgeschützt direkt am Account gelesen, über [\$wsAccount.paymentLimit](/frontend/referenz/module/wsAccount) bzw. `$wsAccount.paymentLimitPerOrder`. Über `allowedPaymentMethods` können nur Zahlarten freigeschaltet werden, die auch für das Firmenkonto selbst verfügbar sind: Zahlarten, die für das Konto gesperrt sind (`blockedPaymentMethods`) oder in der Shop-Konfiguration mit `availableByDefault: false` angelegt und nicht gezielt für das Konto freigeschaltet wurden (`enabledPaymentMethods`), können keiner Berechtigungsgruppe zugewiesen werden (siehe [Konfiguration Zahlungsmethoden](/konfiguration/payment-zahlungsmethoden)). **Fehlercodes** | Fehlercode | Beschreibung | | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `unauthorized` | Der Benutzer verfügt nicht über Admin-Rechte. | | `missingPrivilegeId` | Parameter `privilegeId` fehlt. | | `invalidPrivilegeId` | Ungültige `privilegeId` - die Gruppe existiert nicht und `createMissing` ist nicht gesetzt. | | `invalidType` | Parameter `type` enthält einen ungültigen Wert. | | `paymentMethodNotAllowedByAccount` | Eine Zahlart in `allowedPaymentMethods` ist für das Firmenkonto selbst nicht verfügbar (gesperrt oder nicht freigeschaltet). | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](https://dokumentation.websale.de/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](https://dokumentation.websale.de/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) * [\$wsAccount.paymentLimit](/frontend/referenz/module/wsAccount) **Beispiel** das zeigt, wie die Berechtigungen einer Gruppe inklusive globaler und bestellbezogener Budgetgrenze aktualisiert werden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionUpdatePrivileges = $wsActions.create("UpdatePrivileges") }}
``` *** ### DeletePrivilegeGroup Mit dieser Aktion wird eine bestehende Berechtigungsgruppe gelöscht. Eine Gruppe kann jedoch nicht gelöscht werden, solange ihr noch Mitarbeiterkonten zugewiesen sind. Für diese Aktion sind Admin-Rechte erforderlich. **Anwendungsbeispiel**\ Nutzbar auf der Berechtigungsverwaltungsseite, wenn eine nicht mehr benötigte Berechtigungsgruppe entfernt werden soll. **Parameter** | Name | Beschreibung | | ---- | --------------------------------------------------------- | | `id` | Die ID der Berechtigungsgruppe, die gelöscht werden soll. | **Fehlercodes** | Fehlercode | Beschreibung | | ----------------- | -------------------------------------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `unauthorized` | Der Benutzer verfügt nicht über Admin-Rechte. | | `missingId` | Parameter `id` fehlt. | | `invalidId` | Ungültige `id` - die Berechtigungsgruppe existiert nicht. | | `groupHasMembers` | Die Berechtigungsgruppe kann nicht gelöscht werden, da ihr noch Mitarbeiterkonten zugewiesen sind. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](https://dokumentation.websale.de/frontend/referenz/module/wsAccount) * [\$wsAccount.isLoggedIn](https://dokumentation.websale.de/frontend/referenz/module/wsAccount#%24wsaccount-isloggedin) **Beispiel** das zeigt, wie eine Berechtigungsgruppe über ihre ID gelöscht wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionDeletePrivilegeGroup = $wsActions.create("DeletePrivilegeGroup") }}
``` # Basket Source: https://dokumentation.websale.de/frontend/referenz/aktionen/basket Warenkorb-Aktionen im Überblick: BasketItemAdd, BasketItemUpdate, BasketItemDelete sowie VoucherAdd und VoucherDelete zum Verwalten des Warenkorbs. In diesem Abschnitt werden die verfügbaren Aktionen im Bereich Warenkorb beschrieben. Mit diesen Aktionen können Produkte hinzugefügt, aktualisiert und entfernt sowie Gutscheine verwaltet werden. *** ## Aktionen im Überblick | **Aktion** | **Beschreibung** | | ------------------ | ------------------------------------------------------- | | `BasketItemAdd` | Legt ein Produkt in den Warenkorb. | | `BasketItemUpdate` | Aktualisiert die Menge eines Produkts im Warenkorb. | | `BasketItemDelete` | Entfernt ein Produkt aus dem Warenkorb. | | `VoucherAdd` | Löst einen Gutscheincode im Warenkorb ein. | | `VoucherDelete` | Entfernt einen eingelösten Gutschein aus dem Warenkorb. | *** ## Aktionen ### BasketItemAdd Mit dieser Aktion wird ein Produkt in den Warenkorb gelegt. **Anwendungsbeispiel**\ Nutzbar auf Produktedetail-, Kategorie- oder Merklisten-Seiten, auf denen Produkte direkt in den Warenkorb legen können. **Parameter** | **Name** | **Beschreibung** | | ------------------------ | ------------------------------------------------------------------------------ | | `productId` | Die ID des Produkts, das in den Warenkorb gelegt werden soll. | | `quantity` | Die gewünschte Menge des Produkts. | | `freeFieldscategoryPath` | Optionales Freifeld zur Übergabe des Kategoriepfads, z.B. für Tracking-Zwecke. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | ----------------------------------------------------- | | `missingProductId` | Parameter `productId` fehlt. | | `invalidProductId` | Das Produkt existiert nicht oder ist nicht verfügbar. | **Zugehörige Module, Variablen & Methoden** * [\$wsBasket](/frontend/referenz/module/wsbasket) * [\$wsBasket.items](/frontend/referenz/module/wsbasket#\$wsbasket-items) * [\$wsBasket.lastBasketAction](/frontend/referenz/module/wsbasket#\$wsbasket-lastbasketaction) * [\$wsBasket.lastUpdatedItem](/frontend/referenz/module/wsbasket#\$wsbasket-lastupdateditem) **Beispiel** das zeigt, wie ein Produkt mit Mengenauswahl in den Warenkorb gelegt wird und nach erfolgreicher Ausführung eine Bestätigungsmeldung erscheint. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsActions.current.success and $wsActions.current.name == "BasketItemAdd" }}
Produkt zum Warenkorb hinzugefügt.
{{ /if }} {{ var $myActionBasketItemAdd = $wsActions.create("BasketItemAdd") }}
``` *** ### BasketItemUpdate Mit dieser Aktion wird die Menge eines im Warenkorb enthaltenen Produkts aktualisiert. **Anwendungsbeispiel**\ Nutzbar auf der Warenkorbseite oder im Warenkorb-Offcanvas, wenn Kunden die Menge eines bereits hinzugefügten Produkts anpassen möchten. **Parameter** | **Name** | **Beschreibung** | | -------------- | --------------------------------------------------------------------- | | `basketItemId` | Die ID des Warenkorb-Eintrags, dessen Menge aktualisiert werden soll. | | `quantity` | Die neue Menge des Produkts. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | --------------------- | ---------------------------------------------------------------------------- | | `missingBasketItemId` | Parameter `basketItemId` fehlt. | | `invalidBasketItemId` | Der Warenkorb-Eintrag existiert nicht oder gehört nicht zu diesem Warenkorb. | | `missingQuantity` | Parameter `quantity` fehlt. | **Zugehörige Module, Variablen & Methoden** * [\$wsBasket](/frontend/referenz/module/wsbasket) * [\$wsBasket.items](/frontend/referenz/module/wsbasket#\$wsbasket-items) * [\$wsBasket.lastBasketAction](/frontend/referenz/module/wsbasket#\$wsbasket-lastbasketaction) * [\$wsBasket.lastUpdatedItem](/frontend/referenz/module/wsbasket#\$wsbasket-lastupdateditem) **Beispiel** das zeigt, wie die Menge eines Warenkorb-Eintrags über ein Formular aktualisiert wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionBasketItemUpdate = $wsActions.create("BasketItemUpdate", tag = $myProduct.id) }}
``` *** ### BasketItemDelete Mit dieser Aktion wird ein Produkt aus dem Warenkorb entfernt. **Anwendungsbeispiel**\ Nutzbar auf der Warenkorbseite oder im Warenkorb-Offcanvas, wenn Kunden ein Produkt vollständig aus dem Warenkorb entfernen möchten. **Parameter** | **Name** | **Beschreibung** | | -------------- | -------------------------------------------------------- | | `basketItemId` | Die ID des Warenkorb-Eintrags, der entfernt werden soll. | | `productId` | Die ID des Produkts, das entfernt werden soll. | | `quantity` | Die aktuelle Menge des Produkts. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | --------------------- | ---------------------------------------------------------------------------- | | `missingBasketItemId` | Parameter `basketItemId` fehlt. | | `invalidBasketItemId` | Der Warenkorb-Eintrag existiert nicht oder gehört nicht zu diesem Warenkorb. | **Zugehörige Module, Variablen & Methoden** * [\$wsBasket](/frontend/referenz/module/wsbasket) * [\$wsBasket.items](/frontend/referenz/module/wsbasket#\$wsbasket-items) * [\$wsBasket.lastBasketAction](/frontend/referenz/module/wsbasket#\$wsbasket-lastbasketaction) * [\$wsBasket.lastUpdatedItem](/frontend/referenz/module/wsbasket#\$wsbasket-lastupdateditem) **Beispiel** das zeigt, wie ein Produkt über einen Button aus dem Warenkorb entfernt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionBasketItemDelete = $wsActions.create("BasketItemDelete", tag = $myProduct.id) }}
``` # Checkout Source: https://dokumentation.websale.de/frontend/referenz/aktionen/checkout Checkout-Aktionen für den Bestellablauf: Rechnungs- und Lieferadressen auswählen, zwischenspeichern und in den Bestellprozess übernehmen. In diesem Abschnitt werden die verfügbaren Aktionen im Checkout beschrieben. Mit diesen Aktionen können beispielsweise Rechnungs- und Lieferadressen ausgewählt, zwischengespeichert und übernommen werden. *** ## Aktionen im Überblick | **Aktion** | **Beschreibung** | | ------------------------------------- | ---------------------------------------------------------------------------------- | | `CheckoutAccountTypeSelect` | Legt den Kontotyp für den aktuellen Bestellvorgang fest. | | `CheckoutBillAddressSelect` | Setzt eine gespeicherte Adresse als aktive Rechnungsadresse. | | `CheckoutShippingAddressSelect` | Setzt eine gespeicherte Adresse als aktive Lieferadresse. | | `CheckoutSetDraftAddress` | Speichert eine Adresse temporär als Entwurf (ohne Validierung). | | `CheckoutCommitDraftAddress` | Übernimmt einen Adressentwurf als verbindliche Checkout-Adresse (mit Validierung). | | `CheckoutUseSameShippingAddress` | Setzt die Lieferadresse gleich der Rechnungsadresse. | | `CheckoutUseDifferentShippingAddress` | Aktiviert eine abweichende Lieferadresse. | | `CheckoutSetGuestEmail` | Setzt die E-Mail-Adresse für eine Gastbestellung. | | `CheckoutPaymentUpdate` | Setzt die Zahlungsart für den aktuellen Bestellvorgang. | | `CheckoutShippingMethodUpdate` | Setzt die Versandart für den aktuellen Bestellvorgang. | | `CheckoutConfirm` | Schickt die Bestellung verbindlich ab. | | `RefreshPaymentStatus` | Aktualisiert den Status einer laufenden Zahlung und gibt ihn zurück. | | `CheckoutSetFreeFields` | Setzt die freien Checkout-Felder, beispielsweise die AGB-Zustimmung. | | `CheckoutSetCustomerData` | Setzt Kundendaten im Checkout. | | `CheckoutPseudoCCSelect` | Wählt eine gespeicherte Pseudo-Kreditkarte aus. | | `CheckoutNewsletterSubscribe` | Meldet den Kunden während des Checkouts zum Newsletter an. | | `CheckoutSetVerificationStatus` | Setzt den Verifizierungsstatus der Bestellung. (**Doku folgt**) | | `CheckoutStoreIdSelect` | Setzt einen Markt als Abholort für den aktuellen Bestellvorgang. | *** ## Aktionen ### CheckoutBillAddressSelect Mit dieser Aktion wählt der Kunde eine seiner bereits gespeicherten Adressen als Rechnungsadresse für den aktuellen Bestellvorgang aus. Die Auswahl wird sofort übernommen, es ist keine weitere Bestätigung nötig. **Anwendungsbeispiel**
Nutzbar, um beispielsweise eingeloggten Kunden im Checkout ein Dropdown mit ihren gespeicherten Adressen anzuzeigen, sodass sie eine Rechnungsadresse mit einem Klick auswählen können, ohne erneute Eingabe. **Parameter** | **Name** | **Beschreibung** | | ----------- | ----------------------------------------------------------------- | | `addressId` | Die ID der Adresse, die als Rechnungsadresse gesetzt werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | ------------------------------------------------------------------------------- | | `missingAddressId` | Parameter `addressId` fehlt. | | `invalidAddressId` | Die angegebene Adresse existiert nicht oder gehört nicht zu diesem Kundenkonto. | **Zugehörige Module, Variablen & Methoden** * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [\$wsCheckout.selectedBillAddress](/frontend/referenz/module/wscheckout#\$wscheckout-selectedbilladdress) * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.addresses](/frontend/referenz/module/wsAccount#\$wsaccount-addresses) **Beispiel** das zeigt, wie eingeloggten Kunden ein Dropdown mit ihren gespeicherten Adressen angezeigt wird, über das sie eine Rechnungsadresse auswählen können. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myCheckoutBillAddressSelect = $wsActions.create("CheckoutBillAddressSelect") }}
``` *** ### CheckoutShippingAddressSelect Mit dieser Aktion wählt der Kunde eine seiner bereits gespeicherten Adressen als Lieferadresse für den aktuellen Bestellvorgang aus. Die Aktion ist nur relevant, wenn der Kunde eine abweichende Lieferadresse angeben möchte. **Anwendungsbeispiel**
Nutzbar, wenn ein Kunde eine Bestellung an eine andere Adresse schicken möchte. **Parameter** | **Name** | **Beschreibung** | | ----------- | -------------------------------------------------------------- | | `addressId` | Die ID der Adresse, die als Lieferadresse gesetzt werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | ------------------------------------------------------------------------------- | | `missingAddressId` | Parameter `addressId` fehlt. | | `invalidAddressId` | Die angegebene Adresse existiert nicht oder gehört nicht zu diesem Kundenkonto. | **Zugehörige Module, Variablen & Methoden** * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsAccount.addresses](/frontend/referenz/module/wsAccount#\$wsaccount-addresses) * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [\$wsCheckout.selectedShippingAddress](/frontend/referenz/module/wscheckout#\$wscheckout-selectedshippingaddress) **Beispiel** das zeigt, wie eingeloggten Kunden ein Dropdown mit ihren gespeicherten Adressen angezeigt wird, über das sie eine Lieferadresse auswählen können. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myCheckoutShippingAddressSelect = $wsActions.create("CheckoutShippingAddressSelect") }}
``` *** ### CheckoutSetDraftAddress Mit dieser Aktion wird eine vom Kunden eingegebene Adresse vorläufig gespeichert, ohne dass die Eingaben sofort auf Vollständigkeit oder Korrektheit geprüft werden. Die Draft-Adresse wirkt sich dabei bereits auf die verfügbaren Versand- und Zahlungsarten aus, die auf Basis der Eingaben angepasst werden (relevant für den OnePage-Checkout). Die Adresse gilt zunächst als Entwurf und wird erst durch [CheckoutCommitDraftAddress](#checkoutcommitdraftaddress) als verbindliche Checkout-Adresse übernommen. Der Adresstyp wird direkt im Aktionsnamen angegeben (`bill` oder `shipping`). **Anwendungsbeispiel**
Nutzbar im OnePage-Checkout, um die eingegebene Adresse laufend zwischenzuspeichern, ohne den Kunden sofort mit Validierungsfehlern zu konfrontieren. Die eigentliche Prüfung der Adresse erfolgt erst beim Klick auf “Jetzt kaufen” über [CheckoutCommitDraftAddress](#checkoutcommitdraftaddress). **Parameter** | **Name** | **Beschreibung** | | --------------------- | ------------------------------------------------------------------------------------------- | | `address.(fieldname)` | Die einzelnen Felder der Adresse, beispielsweise `address.firstName` oder `address.street`. | **Zugehörige Module, Variablen & Methoden** * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [\$wsCheckout.draftBillAddressId](/frontend/referenz/module/wscheckout#\$wscheckout-draftbilladdressid) * [\$wsCheckout.draftShippingAddressId](/frontend/referenz/module/wscheckout#\$wscheckout-draftshippingaddressid) **Beispiel** das zeigt, wie eine Rechnungsadresse als Entwurf zwischengespeichert wird, ohne sie sofort zu validieren. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionSetDraftBillAddress = $wsActions.create("CheckoutSetDraftAddress:bill") }}
``` *** ### CheckoutCommitDraftAddress Mit dieser Aktion wird ein zuvor per [CheckoutSetDraftAddress](#checkoutsetdraftaddress) gespeicherter Adressentwurf validiert und als Checkout-Adresse übernommen. Das Verhalten unterscheidet sich je nach Bestelltyp: * Gastbestellung - die eingegebene Adresse wird geprüft und, sofern gültig, direkt für den Checkout übernommen. * Bestellung mit Kundenkonto - die eingegebene Adresse wird geprüft und, sofern gültig, als neue Adresse im Kundenkonto angelegt und gleichzeitig für den aktuellen Checkout ausgewählt. Sind die Daten fehlerhaft oder unvollständig, schlägt die Validierung fehl und der Entwurf bleibt erhalten, sodass der Kunde seine Eingaben korrigieren kann. Der Adresstyp wird direkt im Aktionsnamen angegeben (`bill` oder `shipping`). Diese Aktion bildet zusammen mit [CheckoutSetDraftAddress](#checkoutsetdraftaddress) den typischen Adress-Workflow im OnePage-Checkout:
[CheckoutSetDraftAddress](#checkoutsetdraftaddress) speichert die Eingaben laufend zwischen (ohne Validierung), `CheckoutCommitDraftAddress` schließt den Prozess ab. **Anwendungsbeispiel**
Nutzbar als abschließender Schritt im OnePage-Checkout. Der Kunde hat seine Adresse bereits eingegeben und erst beim Klick auf “Jetzt kaufen” wird geprüft, ob alle Angaben korrekt und vollständig sind. **Parameter** | **Name** | **Beschreibung** | | --------------------- | ------------------------------------------------------------------------------------------- | | `address.(fieldname)` | Die einzelnen Felder der Adresse, beispielsweise `address.firstName` oder `address.street`. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `addressCheckFailed` | Fehler in den Adressdaten. Wird über Sub-Codes konkretisiert:
`minlen` = zu wenig Zeichen
`maxlen` = zu viele Zeichen
`numeric` = ungültige Zeichen
`country` = Land nicht konfiguriert
`zip` = Postleitzahl fehlerhaft | **Zugehörige Module, Variablen & Methoden** * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [\$wsCheckout.isValidShippingAddress()](/frontend/referenz/module/wscheckout#\$wscheckout-isvalidshippingaddress) * [\$wsCheckout.isValidBillAddress()](/frontend/referenz/module/wscheckout#\$wscheckout-isvalidbilladdress) **Beispiel** das zeigt, wie ein Rechnungsadress-Entwurf validiert und als verbindliche Checkout-Adresse übernommen wird. Bei fehlerhaften Eingaben bleibt der Entwurf erhalten und Fehler werden ausgegeben. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionCommitDraftBillAddress = $wsActions.create("CheckoutCommitDraftAddress:bill") }} {{ include "components/errorAlert.htm" with $myAction = $myActionCommitDraftBillAddress }}
``` *** ### CheckoutUseSameShippingAddress Mit dieser Aktion wird festgelegt, dass die Lieferung an dieselbe Adresse wie die Rechnungsadresse erfolgen soll. Eine zuvor eingegebene oder ausgewählte abweichende Lieferadresse wird dadurch nicht gelöscht, aber für den Checkout nicht mehr berücksichtigt. **Anwendungsbeispiel**
Nutzbar, um dem Kunden beispielsweise per Checkbox die Möglichkeit zu geben, Rechnungs- und Lieferadresse mit einem Klick gleichzusetzen, ohne erneute Eingabe. **Zugehörige Module, Variablen & Methoden** * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [\$wsCheckout.useAlternativeShippingAddress](/frontend/referenz/module/wscheckout#\$wscheckout-usealternativeshippingaddress) **Beispiel** das zeigt, wie die Aktion über ein verstecktes Formular ausgelöst wird, das per JavaScript an eine Checkbox gekoppelt werden kann. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionCheckoutUseSameShippingAddress = $wsActions.create("CheckoutUseSameShippingAddress") }}
``` *** ### CheckoutUseDifferentShippingAddress Mit dieser Aktion wird eine abweichende Lieferadresse für den Checkout aktiviert. Sobald sie ausgelöst wurde, wird der Bereich zur Auswahl oder Eingabe einer separaten Lieferadresse relevant. Die Aktion kehrt den Effekt von [CheckoutUseSameShippingAddress](#checkoutusesameshippingaddress) um. **Anwendungsbeispiel**
Nutzbar, wenn der Kunde eine Bestellung an eine andere Adresse liefern lassen möchte, beispielsweise direkt an eine Filiale. **Zugehörige Module, Variablen & Methoden** * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [\$wsCheckout.useAlternativeShippingAddress](/frontend/referenz/module/wscheckout#\$wscheckout-usealternativeshippingaddress) **Beispiel** das zeigt, wie die Aktion über ein verstecktes Formular ausgelöst wird, das per JavaScript an eine Checkbox gekoppelt werden kann. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionCheckoutUseDifferentShippingAddress = $wsActions.create("CheckoutUseDifferentShippingAddress") }}
``` *** ### CheckoutAccountTypeSelect Mit dieser Aktion wird der Kontotyp für den aktuellen Bestellvorgang festgelegt. Der gewählte Typ bestimmt, welche Schritte im Checkout-Prozess angezeigt werden. **Anwendungsbeispiel**
Nutzbar auf der Login-Seite im Checkout-Kontext, um dem Kunden die Möglichkeit zu geben, als Gast zu bestellen, ohne ein Konto anlegen zu müssen. **Parameter** | **Name** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | `accountType` | Der gewünschte Kontotyp. Mögliche Werte: - `guest` - Gastkonto - `new` - Neues Kundenkonto - `registered` - Registrierter Kunde | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | -------------------- | ------------------------------------- | | `invalidAccountType` | Der angegebene Kontotyp ist ungültig. | **Zugehörige Module, Variablen & Methoden** * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [\$wsCheckout.accountType](/frontend/referenz/module/wscheckout#\$wscheckout-accounttype) **Beispiel** das zeigt, wie der Kontotyp auf “`guest`” gesetzt wird, um eine Gastbestellung zu ermöglichen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionCheckoutAccountTypeSelect = $wsActions.create("CheckoutAccountTypeSelect") }}
``` *** ### CheckoutSetGuestEmail Mit dieser Aktion wird die E-Mail-Adresse für eine Gastbestellung gesetzt. Sie ist nur relevant, wenn der Kontotyp auf “`guest`” gesetzt wurde. **Anwendungsbeispiel**
Nutzbar im Checkout, wenn ein Kunde als Gast bestellen möchte und dafür seine E-Mail-Adresse angeben muss. **Parameter** | **Name** | **Beschreibung** | | ------------ | ---------------------------------- | | `guestEmail` | Die E-Mail-Adresse des Gastkunden. | **Fehlercodes** | **Code** | **Beschreibung** | | ------------------ | ------------------------------------------------------------ | | `missingEmail` | Parameter `guestEmail` fehlt. | | `emailCheckFailed` | Parameter `guestEmail` enthält keine gültige E-Mail-Adresse. | **Zugehörige Module, Variablen & Methoden** * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [\$wsCheckout.guestMail](/frontend/referenz/module/wscheckout#\$wscheckout-guestmail) * [\$wsCheckout.accountType](/frontend/referenz/module/wscheckout#\$wscheckout-accounttype) **Beispiel** das zeigt, wie ein Gastkunde seine E-Mail-Adresse im Checkout eingibt, inklusive Fehlerausgabe bei ungültiger Eingabe. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionCheckoutSetGuestEmail = $wsActions.create("CheckoutSetGuestEmail") }}
``` *** ### CheckoutShippingMethodUpdate Mit dieser Aktion wird die Versandart für den aktuellen Bestellvorgang gesetzt. **Anwendungsbeispiel**
Nutzbar im Checkout, um dem Kunden eine Liste der verfügbaren Versandarten anzuzeigen, aus der er eine auswählen kann. **Parameter** | **Name** | **Beschreibung** | | ------------------ | -------------------------------------------------- | | `shippingMethodId` | Die ID der Versandart, die ausgewählt werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------------- | ---------------------------------------------- | | `missingShippingMethodId` | Parameter `shippingMethodId` fehlt. | | `invalidShippingMethodId` | Die angegebene Versandart ist nicht verfügbar. | **Zugehörige Module, Variablen & Methoden** * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [\$wsCheckout.selectedShippingMethod](/frontend/referenz/module/wscheckout#\$wscheckout-selectedshippingmethod) * [\$wsCheckout.isValidShippingMethod()](/frontend/referenz/module/wscheckout#\$wscheckout-isvalidshippingmethod) * [\$wsCheckout.problems.shippingMethod](/frontend/referenz/module/wscheckout#\$wscheckout-problems-shippingmethod) **Beispiel** das zeigt, wie alle verfügbaren Versandarten als Auswahlliste dargestellt werden, wobei nicht verfügbare Optionen deaktiviert sind. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionCheckoutShippingMethodUpdate = $wsActions.create("CheckoutShippingMethodUpdate") }}
{{ foreach $myShipping in $wsConfig.shippingMethods }} {{ /foreach }}
``` *** ### CheckoutConfirm Mit dieser Aktion wird die Bestellung verbindlich abgeschickt. Sie ist der abschließende Schritt im Checkout-Prozess und setzt voraus, dass alle erforderlichen Angaben (Adresse, Zahlungsart und Versandart) vollständig und gültig sind. **Anwendungsbeispiel**
Nutzbar als “Jetzt kaufen”-Button auf der Bestellübersichtsseite, über den der Kunde die Bestellung verbindlich aufgibt. **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ----------------- | ------------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt und es ist keine Gast-E-Mail vorhanden. | | `invalidCheckout` | Der Checkout ist nicht vollständig oder enthält ungültige Angaben. | **Zugehörige Module, Variablen & Methoden** * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [\$wsCheckout.isValid](/frontend/referenz/module/wscheckout#\$wscheckout-isvalid) * [\$wsCheckout.problems](/frontend/referenz/module/wscheckout#\$wscheckout-problems) * [\$wsCheckout.isExpressCheckoutLocked](/frontend/referenz/module/wscheckout#\$wscheckout-isexpresscheckoutlocked) **Beispiel** das zeigt, wie die Bestellung über einen Button verbindlich abgeschickt wird, sofern der Kunde eingeloggt oder als Gast identifiziert ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionCheckoutConfirm = $wsActions.create("CheckoutConfirm") }}
``` *** ### RefreshPaymentStatus Mit dieser Aktion wird der Status einer Zahlung manuell aktualisiert. Die Aktion fragt den aktuellen Stand ab und gibt ihn im JSON-Format zurück. Eine Erfolgsmeldung des Zahlungsdienstleisters bedeutet dabei noch nicht, dass die Zahlung im Shop gültig ist. Meldet PayPal beispielsweise eine erfolgreiche Zahlung, muss der Shop diese nicht zwingend akzeptieren. Ist die 3DS-Prüfung nicht durchgelaufen, lehnt der Shop die Zahlung aus Sicherheitsgründen ab. Außerdem kann die Zahlung beim Einzug des Betrags noch in einen Fehler laufen. Der zurückgegebene Status ist deshalb die Bewertung des Shops und nicht die Rückmeldung des Zahlungsdienstleisters. **Anwendungsbeispiel**
Nutzbar auf der Wartseite einer Online-Zahlung. Der Kunde darf erst dann auf die Bestellbestätigung geführt werden, wenn diese Aktion die Zahlung als fehlerfrei abgeschlossen meldet. Meldet sie einen Fehler oder einen Abbruch, gehört der Kunde in die Fehlerbehandlung. **Antwort** Die Antwort enthält immer das Feld `paymentStatus`. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "paymentStatus": "pending" } ``` | **Wert** | **Bedeutung** | | ----------------- | -------------------------------------------------------------------------------------------- | | `unknown` | Es gibt keine Zahlung, deren Status abgefragt werden kann. | | `redirected` | Der Kunde wurde zum Zahlungsdienstleister weitergeleitet, ein Ergebnis liegt noch nicht vor. | | `pending` | Die Zahlung wurde angenommen, ist aber noch in Bearbeitung. | | `finished` | Die Zahlung ist abgeschlossen und vom Shop akzeptiert. | | `canceledByUser` | Die Zahlung wurde vom Kunden abgebrochen. | | `canceledByAdmin` | Die Zahlung wurde im Backend abgebrochen. | | `error` | Bei der Zahlung ist ein Fehler aufgetreten oder der Shop hat sie abgelehnt. | Die Zustände entsprechen den Zahlungsstatus, die auch die REST-API für [Bestellungen](/schnittstellen/admin-interface-api/api-referenz-bestellungen) und Transaktionen verwendet. Dort werden sie numerisch geführt, in dieser Antwort als Text. Neben den hier aufgeführten Werten kann die Transaktion weitere Status annehmen, beispielsweise nach einer Rückerstattung im Backend. Behandeln Sie unbekannte Werte im Template daher als offenen Status. **Fehler in der Antwort** Hat `paymentStatus` den Wert `error`, enthält die Antwort zusätzlich das Feld `errors` mit einer Liste der aufgetretenen Fehler. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "paymentStatus": "error", "errors": [ { "code": "", "subCode": "", "field": "", "text": "", "details": {} } ] } ``` | **Feld** | **Typ** | **Beschreibung** | | --------- | ------- | --------------------------------------------------------------------------------- | | `code` | string | Fehlercode. | | `subCode` | string | Optionaler Code zur genaueren Bestimmung von `code`. | | `field` | string | Feld, in dem der Fehler aufgetreten ist. Bei Zahlungsfehlern ohne Feldbezug leer. | | `text` | string | Anzeigetext des Fehlers. | | `details` | object | Zusätzliche Angaben zum Fehler. | Die Liste ist bisher immer leer. Die Befüllung wird erst später umgesetzt, das Format steht aber bereits fest und kann im Frontend berücksichtigt werden. Werten Sie den Fehlerfall deshalb über den Statuswert `error` aus und nicht über die Länge der Liste. **Zugehörige Module, Variablen & Methoden** * [\$wsActions](/frontend/referenz/module/wsactions) * [API-Referenz Bestellungen](/schnittstellen/admin-interface-api/api-referenz-bestellungen) *** ### CheckoutSetFreeFields Mit dieser Aktion werden die freien Checkout-Felder gesetzt, beispielsweise die Zustimmung zu den AGB oder ein Kommentarfeld. Die Aktion wird typischerweise zusammen mit `CheckoutConfirm` auf der Bestellübersichtsseite eingesetzt. **Anwendungsbeispiel**
Nutzbar auf der Bestellübersichtsseite, um dem Kunden beispielsweise eine Checkbox zur Zustimmung der AGB anzuzeigen, die vor dem Abschicken der Bestellung akzeptiert werden muss. **Parameter** | **Name** | **Beschreibung** | | ----------------------- | -------------------------------------------------------------------------------------- | | `freeFields.(id).value` | Der Wert des freien Felds, beispielsweise `freeFields.agb.value` für die AGB-Checkbox. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ---------------------- | --------------------------------------- | | `missingRequiredField` | Ein Pflichtfeld wurde nicht ausgefüllt. | **Zugehörige Module, Variablen & Methoden** * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [\$wsCheckout.freeFields](/frontend/referenz/module/wscheckout#\$wscheckout-freefields) **Beispiel** das zeigt, wie eine AGB-Checkbox als freies Checkout-Feld eingebunden wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionSetFreeFields = $wsActions.create("CheckoutSetFreeFields") }}
{{ foreach $myField in $wsCheckout.freeFields }} {{ if $myField.id == "agb" }} {{ /if }} {{ /foreach }}
``` *** ### CheckoutSetCustomerData Mit dieser Aktion werden zusätzliche Kundendaten im Checkout gesetzt. Die Felder werden dynamisch aus der Konfiguration geladen und können gruppiert oder ungruppiert vorliegen. **Anwendungsbeispiel**
Nutzbar im Checkout, um konfigurierte Kundendaten-Felder (beispielsweise Firmenname oder Telefon) abzufragen, die über die Standardadresse hinausgehen. **Parameter** | **Name** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `(dynamisch)` | Die Felder werden aus [\$wsCheckout.customerData](/frontend/referenz/module/wscheckout#\$wscheckout-customerdata) geladen und variieren je nach Shop-Konfiguration. | **Zugehörige Module, Variablen & Methoden** * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [\$wsCheckout.customerData](/frontend/referenz/module/wscheckout#\$wscheckout-customerdata) * [\$wsCheckout.customerData.fieldGroups](/frontend/referenz/module/wscheckout#\$wscheckout-customerdata-fieldgroups) **Beispiel** das zeigt, wie gruppierte Kundendaten-Felder dynamisch gerendert und Fehler feldspezifisch ausgegeben werden: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $setCustomerDataAction = $wsActions.create("CheckoutSetCustomerData") }}
{{ foreach $error in $setCustomerDataAction.errors }}
{{= $error.text | ifNull($error.code) }}
{{ /foreach }} {{ foreach $group in $wsCheckout.customerData.groupedFields }} {{ if $group.hidden == false }} {{ foreach $field in $group.fields }} {{include "components/src/customerDataField.htm" with $field=$field }} {{ if $setCustomerDataAction.errorsByField[$field.name] }} {{ foreach $fieldError in $setCustomerDataAction.errorsByField[$field.name] }}
{{= $fieldError.code }}{{ if $fieldError.subCode }} ({{= $fieldError.subCode }}){{ /if }}
{{ /foreach }} {{ /if }} {{ /foreach }} {{ /if }} {{ /foreach }}
``` *** ### CheckoutPseudoCCSelect Mit dieser Aktion wählt der Kunde eine seiner gespeicherten Pseudo-Kreditkarten für den aktuellen Bestellvorgang aus. Die Aktion ist ausschließlich für die Computop-Kreditkarten-Integration relevant. **Anwendungsbeispiel**
Nutzbar im Checkout, wenn der Kunde eine zuvor hinterlegte Kreditkarte verwenden möchte, ohne die Kartendaten erneut einzugeben. Der Wert `0` steht für “keine gespeicherte Karte verwenden”. **Parameter** | **Name** | **Beschreibung** | | ------------ | -------------------------------------------------------------------------------- | | `pseudoCCId` | Die ID der gespeicherten Pseudo-Kreditkarte. Der Wert `0` wählt keine Karte aus. | **Zugehörige Module, Variablen & Methoden** * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [\$wsCheckout.selectedPseudoCC](/frontend/referenz/module/wscheckout#\$wscheckout-selectedpseudocc) **Beispiel** das zeigt, wie gespeicherte Kreditkarten zur Auswahl angezeigt werden, inklusive der Option, keine Karte zu verwenden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myAction = $wsActions.create("CheckoutPseudoCCSelect") }}
{{ if $myAction.error }} {{ foreach $error in $myAction.errors }}
{{= $error.text | ifNull($error.code) }}
{{ /foreach }} {{ /if }} {{ foreach $card in $wsAccount.pseudoCreditCards }} {{ /foreach }}
``` *** ### CheckoutNewsletterSubscribe Mit dieser Aktion wird ein Kunde während des Bestellvorgangs für den Newsletter angemeldet. Sie funktioniert analog zur Aktion [NewsletterSubscribe](/frontend/referenz/aktionen/newsletter). Parameter, Fehlercodes und das Feldübergabe-Verhalten sind identisch. **Anwendungsbeispiel**
Nutzbar im Checkout, um Kunden während des Bestellvorgangs die Möglichkeit zu geben, sich für den Newsletter anzumelden, beispielsweise über eine Checkbox auf der Bestellübersichtsseite. **Parameter** | Name | Beschreibung | | -------------------- | ------------------------------------------------------------------- | | `email` | Die E-Mail-Adresse, die für den Newsletter angemeldet werden soll. | | `targetGroupId.(id)` | Optionale Zielgruppen-ID, für die der Kunde angemeldet werden soll. | **Fehlercodes** | Fehlercode | Beschreibung | | ---------------------- | ------------------------------------------------------------- | | `missingEmail` | Parameter `email` fehlt. | | `emailCheckFailed` | Die angegebene E-Mail-Adresse ist ungültig. | | `accountAlreadyExists` | Die E-Mail-Adresse ist bereits für den Newsletter angemeldet. | **Zugehörige Module, Variablen & Methoden** * [\$wsNewsletter](/frontend/referenz/module/wsnewsletter) * [\$wsNewsletter.getTargetGroups()](/frontend/referenz/module/wsnewsletter#\$wsnewsletter-gettargetgroups)
**Beispiel** das zeigt, wie ein Kunde im Checkout eine Zielgruppe auswählt und sich für den Newsletter anmeldet. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionCheckoutNewsletterSubscribe = $wsActions.create("CheckoutNewsletterSubscribe") }}
{{ if $myActionCheckoutNewsletterSubscribe.success }}
Newsletter erfolgreich abonniert.
{{ /if }} {{ foreach $myNewsletterList in $wsNewsletter.getTargetGroups() }} {{ /foreach }}
``` *** ### CheckoutStoreIdSelect Mit dieser Aktion wählt der Kunde einen Markt als Abholort für den aktuellen Bestellvorgang aus. Die Aktion ist nur relevant, wenn eine Versandart vom Typ `pickup` ausgewählt wurde. Bei der Auswahl wird geprüft, ob alle Produkte im gewählten Markt verfügbar sind. Ist das nicht der Fall, wird die Aktion nicht ausgeführt und es wird ein Fehler zurückgegeben.
Wurde kein Markt ausgewählt, wird standardmäßig der Markt aus der allgemeinen [Session-Auswahl](/frontend/referenz/aktionen/stores#selectstore) verwendet. **Anwendungsbeispiel**
Nutzbar, wenn der Kunde eine Bestellung direkt in einem Markt abholen möchte und im Checkout aus den verfügbaren Click & Collect-Märkten wählen soll. **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `reservationFailed` | Die Artikel sind im gewählten Markt nicht verfügbar. Details zum betroffenen Produkt werden über `error.details.productId` zurückgegeben. | **Zugehörige Module, Variablen & Methoden** * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [\$wsCheckout.selectedStoreID](/frontend/referenz/module/wscheckout#\$wscheckout-selectedstoreid) * [\$wsCheckout.selectedShippingMethod](/frontend/referenz/module/wscheckout#\$wscheckout-selectedshippingmethod) * [\$wsStores](/frontend/referenz/module/wsstores) * [\$wsStores.loadAllStores()](/frontend/referenz/module/wsstores#\$wsstores-loadallstores) * [\$wsConfig.shippingMethods](/frontend/referenz/module/wsconfig#\$wsconfig-shippingmethods) **Beispiel,** das für jede Versandart vom Typ `pickup` ein Dropdown mit allen Click & Collect-fähigen Märkten zeigt. Es setzt den gewählten Markt per `CheckoutStoreIdSelect` als Abholort, inklusive Fehlerbehandlung bei nicht verfügbaren Artikeln im gewählten Markt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionCheckoutStoreIdSelect = $wsActions.create("CheckoutStoreIdSelect") }} {{ foreach $myShipping in $wsConfig.shippingMethods }} {{ if $wsCheckout.selectedShippingMethod == $myShipping.id and $myShipping.type == "pickup" }}
{{ if $myActionCheckoutStoreIdSelect.error }} {{ foreach $myError in $myActionCheckoutStoreIdSelect.errors }} {{ if $myError.code == "reservationFailed" }}
Artikel im Store nicht verfügbar: {{= $myError.details.productId }}
{{ /if }} {{ /foreach }} {{ /if }} {{ /if }} {{ /foreach }} ``` *** ## Weiterführende Links * [\$wsActions](/frontend/referenz/module/wsactions) * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [\$wsStores](/frontend/referenz/module/wsstores) * [payment - Zahlungsmethoden](/konfiguration/payment-zahlungsmethoden) # Consent Source: https://dokumentation.websale.de/frontend/referenz/aktionen/consent Consent-Aktionen für den Cookie-Banner: Einwilligung des Nutzers zu nicht-essenziellen Cookies und Diensten setzen oder nachträglich ändern. In diesem Abschnitt werden die verfügbaren Aktionen im Bereich Consent beschrieben. Mit diesen Aktionen kann die Zustimmung des Nutzers zu nicht-essenziellen Cookies und Diensten gesetzt oder geändert werden. *** ## Aktionen im Überblick | **Aktion** | **Beschreibung** | | --------------- | ---------------------------------------------------------------------------- | | `ConsentChange` | Setzt oder ändert die Zustimmung zu nicht-essenziellen Cookies und Diensten. | *** ## Aktionen ### ConsentChange Mit dieser Aktion wird die Zustimmung des Nutzers zu nicht-essenziellen Cookies gesetzt oder geändert. Die Zustimmung kann auf oberster Ebene (gesamtes Consent-Objekt), auf Gruppenebene oder auf Ebene einzelner Dienste innerhalb einer Gruppe gesteuert werden. **Anwendungsbeispiel**\ Nutzbar, um z.B. in einem Cookie-Banner dem Nutzer die Möglichkeit zu geben, seine Zustimmung für alle Cookies auf einmal, für bestimmte Gruppen (z.B. “Marketing”, “Statistik”) oder für einzelne Dienste (z.B. “Google Analytics”) gezielt zu erteilen oder zu widerrufen. **Parameter** | **Parameter** | **Beschreibung** | | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `consent` | Setzt die Zustimmung auf oberster Ebene für alle nicht-essenziellen Cookies. | | `groups.` | Setzt die Zustimmung für eine bestimmte Consent-Gruppe. `` steht für den Namen der jeweiligen Gruppe. | | `groups..services.` | Setzt die Zustimmung für einen einzelnen Dienst innerhalb einer Gruppe. `` steht für den Namen des jeweiligen Dienstes. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ---------------- | -------------------------------------------------------- | | `invalidGroup` | Die angegebene Gruppe existiert nicht oder ist ungültig. | | `invalidService` | Der angegebene Dienst existiert nicht oder ist ungültig. | **Zugehörige Module, Variablen & Methoden** * [\$wsConsent](/frontend/referenz/module/wsconsent) * [\$wsConsent.groups](/frontend/referenz/module/wsconsent#\$wsconsent-groups) * [\$wsConsent.services](/frontend/referenz/module/wsconsent#\$wsconsent-services) **Beispiel** das zeigt, wie in einem Cookie-Banner die Zustimmung pro Gruppe und pro Dienst über Checkboxen gesteuert wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionConsentChange = $wsActions.create("ConsentChange") }}
{{ foreach $myConsentGroup in $wsConsent.groups }} {{ foreach $myConsentService in $myConsentGroup.services }} {{ /foreach }} {{ /foreach }}
``` # DirectOrder Source: https://dokumentation.websale.de/frontend/referenz/aktionen/directorder DirectOrder-Aktionen für die Direktbestellung: Produkte per Artikelnummer in eine Bestellliste eintragen, ändern und in den Warenkorb übernehmen. In diesem Abschnitt werden die verfügbaren Aktionen im Bereich Direktbestellung beschrieben. Mit diesen Aktionen können Produkte pro Artikelnummer direkt in eine Bestellliste eingetragen, aktualisiert und in den Warenkorb übernommen werden. *** ## Aktionen im Überblick | **Aktion** | **Beschreibung** | | ------------------------ | ---------------------------------------------------------------- | | `DirectOrderAdd` | Fügt ein Produkt per Artikelnummer zur Direktbestellliste hinzu. | | `DirectOrderUpdate` | Aktualisiert die Menge eines Produkts in der Direktbestellliste. | | `DirectOrderDelete` | Entfernt ein Produkt aus der Direktbestellliste. | | `DirectOrderAddLines` | Fügt eine weitere Eingabezeile zur Direktbestellliste hinzu. | | `DirectOrderDeleteLines` | Entfernt die letzte Eingabezeile aus der Direktbestellliste. | *** ## Aktionen ### DirectOrderAdd Mit dieser Aktion wird ein Produkt per Artikelnummer zur Direktbestellliste hinzugefügt. Nach erfolgreicher Ausführung wird das Produkt mit seinen Informationen in der Liste angezeigt. **Anwendungsbeispiel**\ Nutzbar auf der Direktbestellseite, auf der Kunden Produkte schnell per Artikelnummer suchen und zur Bestellliste hinzufügen können, ohne die Produktdetailseite aufrufen zu müssen. **Parameter** | **Name** | **Beschreibung** | | -------- | ------------------------------------------------------------ | | `id` | Die Artikelnummer des Produkts, das hinzugefügt werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------------ | ----------------------------------------- | | `errorsByField.id` | Fehler bei der Eingabe der Artikelnummer. | | `errorsByField.quantity` | Fehler bei der Eingabe der Menge. | **Zugehörige Module, Variablen & Methoden** * [\$wsDirectOrder](/frontend/referenz/module/wsdirectorder) * [\$wsDirectOrder.items](/frontend/referenz/module/wsdirectorder#\$wsdirectorder-items) * [\$wsDirectOrders.currentLines](/frontend/referenz/module/wsdirectorder#\$wsdirectorder-currentlines) **Beispiel** das zeigt, wie ein Produkt über ein Artikelnummer-Eingabefeld zur Direktbestellliste hinzugefügt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionDirectOrderAdd = $wsActions.create("DirectOrderAdd", tag=string($myDirectOrderProduct)) }}
``` *** ### DirectOrderUpdate Mit dieser Aktion wird die Menge eines Produkts in der Direktbestellliste aktualisiert. **Anwendungsbeispiel**\ Nutzbar auf der Direktbestellseite, wenn ein Kunde die Menge eines bereits eingetragenen Produkts anpassen möchte. **Parameter** | **Name** | **Beschreibung** | | ---------- | ---------------------------- | | `quantity` | Die neue Menge des Produkts. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------------ | --------------------------------- | | `errorsByField.quantity` | Fehler bei der Eingabe der Menge. | **Zugehörige Module, Variablen & Methoden** * [\$wsDirectOrder](/frontend/referenz/module/wsdirectorder) * [\$wsDirectOrder.items](/frontend/referenz/module/wsdirectorder#\$wsdirectorder-items) **Beispiel** das zeigt, wie die Menge eines Produkts in der Direktbestellliste über ein Eingabefeld aktualisiert wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionDirectOrderUpdate = $wsActions.create("DirectOrderUpdate", tag=string($myDirectOrderProduct)) }} ``` *** ### DirectOrderDelete Mit dieser Aktion wird ein Produkt aus der Direktbestellliste entfernt. **Anwendungsbeispiel**\ Nutzbar auf der Direktbestellseite, wenn ein Kunde ein Produkt aus der Bestellliste entfernen möchte. **Parameter** | **Name** | **Beschreibung** | | -------- | --------------------------------------------------------- | | `id` | Die Artikelnummer des Produkts, das entfernt werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | ----------------------------------------- | | `errorsByField.id` | Fehler bei der Eingabe der Artikelnummer. | **Zugehörige Module, Variablen & Methoden** * [\$wsDirectOrder](/frontend/referenz/module/wsdirectorder) * [\$wsDirectOrder.items](/frontend/referenz/module/wsdirectorder#\$wsdirectorder-items) **Beispiel** das zeigt, wie ein Produkt über einen Button aus der Direktbestellliste entfernt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionDirectOrderDelete = $wsActions.create("DirectOrderDelete", tag=string($myDirectOrderProduct)) }} ``` *** ### DirectOrderAddLines Mit dieser Aktion wird eine weitere Eingabezeile zur Direktbestellliste hinzugefügt, sodass der Kunde mehr Produkte auf einmal eintragen kann. **Anwendungsbeispiel**\ Nutzbar auf der Direktbestellseite, wenn ein Kunde mehr Produkte eintragen möchte als aktuell Zeilen vorhanden sind. **Zugehörige Module, Variablen & Methoden** * [\$wsDirectOrder](/frontend/referenz/aktionen/directorder) * [\$wsDirectOrders.currentLines](/frontend/referenz/module/wsdirectorder#\$wsdirectorder-currentlines) **Beispiel** das zeigt, wie über einen Button eine neue Eingabezeile zur Direktbestellliste hinzugefügt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionDirectOrderAddLines = $wsActions.create("DirectOrderAddLines") }}
``` *** ### DirectOrderDeleteLines Mit dieser Aktion wird die letzte Eingabezeile aus der Direktbestellliste entfernt. Die Aktion ist nur verfügbar, wenn mehr als fünf Zeilen vorhanden sind. **Anwendungsbeispiel**\ Nutzbar auf der Direktbestellseite, wenn ein Kunde zu viele Zeilen hinzugefügt hat und diese wieder entfernen möchte. **Zugehörige Module, Variablen & Methoden** * [\$wsDirectOrder](/frontend/referenz/aktionen/directorder) * [\$wsDirectOrders.currentLines](/frontend/referenz/module/wsdirectorder#\$wsdirectorder-currentlines) **Beispiel** das zeigt, wie die letzte Eingabezeile über einen Button entfernt wird, sofern mehr als fünf Zeilen vorhanden sind. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsDirectOrder.currentLines > 5 }} {{ var $myActionDirectOrderDeleteLines = $wsActions.create("DirectOrderDeleteLines") }}
{{ /if }} ``` # Inquiry Source: https://dokumentation.websale.de/frontend/referenz/aktionen/inquiry Inquiry-Aktionen für Anfragen: Kontakt- und Anfrageformulare sowie Frage-zum-Produkt-Formulare im Frontend absenden und auswerten. In diesem Abschnitt werden die verfügbaren Aktionen im Bereich Inquiry beschrieben. Mit diesen Aktionen können z.B. Kontakt- oder Anfrage-Formulare abgesendet werden. *** ## Aktionen im Überblick | **Aktion** | **Beschreibung** | | -------------- | -------------------------------------------------------------- | | `InquirySend` | Sendet ein Anfrage-Formular mit den angegebenen Parametern ab. | | `InquiryCheck` | Prüft die Eingaben eines Formulars, ohne es abzusenden. | *** ## Aktionen ### InquirySend Mit dieser Aktion wird ein Anfrage-Formular abgesendet. Dabei werden die übermittelten Eingaben geprüft und die Anfrage verarbeitet. Schlägt die Verarbeitung fehl, wird ein entsprechender Fehler zurückgegeben, sodass der Nutzer seine Eingaben korrigieren kann. **Anwendungsbeispiel**\ Nutzbar, um z.B. ein Kontaktformular auf einer Seite einzubinden, über das Kunden eine Anfrage stellen können. Nach dem Klick auf “Absenden” wird das Formular validiert und die Anfrage übermittelt. **Parameter** | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------- | | `email` | Die E-Mail-Adresse des Absenders. | | `formId` | Die ID des abzusendenden Formulars. | **Fehler** | **Fehlercode** | **Beschreibung** | | --------------------- | ---------------------------------------------------------------------------- | | `missingEmail` | Es wurde keine E-Mail-Adresse angegeben. | | `emailCheckFailed` | Die angegebene E-Mail-Adresse ist ungültig oder konnte nicht geprüft werden. | | `emptyForm` | Das Formular enthält keine Eingaben. | | `missingFormId` | Es wurde keine Formular-ID übergeben. | | `invalidFormId` | Die angegebene Formular-ID ist nicht gültig. | | `formCheckFailed` | Die Formularprüfung ist fehlgeschlagen. | | `createInquiryFailed` | Die Anfrage konnte nicht erstellt werden. | **Zugehörige Module, Variablen & Methoden** * [\$wsForm](/frontend/referenz/module/wsform) * [\$wsForm.inquiryId](/frontend/referenz/module/wsform#\$wsform-inquiryid) * [\$wsForm.loadType()](/frontend/referenz/module/wsform#\$wsform-loadtype) * [\$wsForm.load()](/frontend/referenz/module/wsform#\$wsform-load) **Beispiel,** das die Aktion erstellt, per Hidden-Input an das Formular bindet und nach dem Absenden auf Erfolg oder Fehler prüft. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cMyInquirySendAction = $wsActions.create('InquirySend') }}
{{ if $cMyInquirySendAction.success }}
%%InquirySuccessTxt%%
{{ else }} {{ /if }}
``` *** ### InquiryCheck Mit dieser Aktion werden die Eingaben eines Formulars geprüft, ohne die Anfrage tatsächlich abzusenden. Die geprüften Feldwerte werden dabei in `$myField.value` zurückgeschrieben und können im Frontend wiederverwendet werden. **Anwendungsbeispiel**\ Nutzbar, um Formulareingaben bereits vor dem endgültigen Absenden zu validieren und dem Nutzer direktes Feedback zu seinen Eingaben zu geben. **Parameter** | **Name** | **Beschreibung** | | -------- | ---------------------------------- | | `email` | Die E-Mail-Adresse des Absenders. | | `formId` | Die ID des zu prüfenden Formulars. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | -------------------------------------------- | | `missingEmail` | Es wurde keine E-Mail-Adresse angegeben. | | `emailCheckFailed` | Die angegebene E-Mail-Adresse ist ungültig. | | `missingFormId` | Es wurde keine Formular-ID übergeben. | | `invalidFormId` | Die angegebene Formular-ID ist nicht gültig. | | `formCheckFailed` | Die Formularprüfung ist fehlgeschlagen. | **Zugehörige Module, Variablen & Methoden** * [\$wsForm](/frontend/referenz/module/wsform) * [\$wsForm.loadType()](/frontend/referenz/module/wsform#\$wsform-loadtype) **Beispiel** folgt. # Inventory Source: https://dokumentation.websale.de/frontend/referenz/aktionen/inventory Inventory-Aktionen für Lagerbestände: Produktreservierungen erneuern und Benachrichtigungen bei Wiederverfügbarkeit von Artikeln verwalten. In diesem Abschnitt werden die verfügbaren Aktionen im Bereich `Inventory` beschrieben. Mit diesen Aktionen können Produktreservierungen erneuert und Benachrichtigungen bei Wiederverfügbarkeit verwaltet werden. *** ## Aktionen im Überblick | **Aktion** | **Beschreibung** | | ----------------------------- | ----------------------------------------------------------------------- | | `InventoryReserve` | Erneuert die Reservierung eines Produkts im Warenkorb. | | `BackInStockActivateNotify` | Aktiviert eine Benachrichtigung, wenn ein Produkt wieder verfügbar ist. | | `BackInStockDeactivateNotify` | Deaktiviert eine bestehende Wiedervorrätig-Benachrichtigung. | *** ## Aktionen ### InventoryReserve Mit dieser Aktion wird die Reservierung eines Produkts im Warenkorb erneuert. Sie ist nur relevant, wenn die Reservierungsdauer eines Artikels abgelaufen ist und der Kunde die Reservierung verlängern möchte. **Anwendungsbeispiel**\ Nutzbar auf der Warenkorbseite, wenn die Reservierungszeit eines Artikels abgelaufen ist und dem Kunden die Möglichkeit gegeben werden soll, die Reservierung zu erneuern. **Parameter** | **Name** | **Beschreibung** | | -------------- | ------------------------------------------------------------------------ | | `basketItemId` | Die ID des Warenkorb-Eintrags, dessen Reservierung erneuert werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | --------------------- | ---------------------------------------------------------------------------------------------- | | `missingBasketItemId` | Parameter `basketItemId` fehlt. | | `invalidBasketItemId` | Der Warenkorb-Eintrag existiert nicht oder gehört nicht zu diesem Warenkorb. | | `reservationFailed` | Die Reservierung konnte nicht erneuert werden, z.B. weil das Produkt nicht mehr verfügbar ist. | **Zugehörige Module, Variablen & Methoden** * [\$wsInventory](/frontend/referenz/module/wsinventory) * [\$wsInventory.load()](/frontend/referenz/module/wsinventory#\$wsinventory-load) * [\$wsInventory.loadReservation()](/frontend/referenz/module/wsinventory#\$wsinventory-loadreservation) * [\$wsBasket.items](/frontend/referenz/module/wsbasket#\$wsbasket-items) **Beispiel** das zeigt, wie einem Kunden bei abgelaufener Reservierung die Möglichkeit gegeben wird, diese über einen Button zu erneuern. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myReservation = $wsInventory.loadReservation($myProduct.id) }} {{ if $myReservation and $myReservation.duration == 0 }} {{ var $myActionInventoryReserve = $wsActions.create("InventoryReserve", tag=$myProduct.id) }}
{{ /if }} ``` *** ### BackInStockActivateNotify Mit dieser Aktion wird eine Benachrichtigung aktiviert, die den Kunden per E-Mail informiert, sobald ein ausverkauftes Produkt wieder verfügbar ist. **Anwendungsbeispiel**\ Nutzbar auf der Produktdetailseite, wenn ein Produkt ausverkauft ist und der Kunde benachrichtigt werden möchte, sobald es wieder bestellbar ist. **Parameter** | **Name** | **Beschreibung** | | ----------- | ------------------------------------------------------------------------ | | `productId` | Die ID des Produkts, für das die Benachrichtigung aktiviert werden soll. | | `email` | Die E-Mail-Adresse, an die die Benachrichtigung gesendet werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | ------------------------------------------- | | `missingProductId` | Parameter `productId` fehlt. | | `missingEmail` | Parameter `email` fehlt. | | `emailCheckFailed` | Die angegebene E-Mail-Adresse ist ungültig. | **Zugehörige Module, Variablen & Methoden** * [\$wsInventory](/frontend/referenz/module/wsinventory) * [\$wsAccount.backInStockList](/frontend/referenz/module/wsAccount#\$wsaccount-backinstocklist) **Beispiel** das zeigt, wie ein Kunde eine Benachrichtigung für ein ausverkauftes Produkt aktivieren kann. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionBackInStockActivateNotify = $wsActions.create("BackInStockActivateNotify") }}
``` *** ### BackInStockDeactivateNotify Mit dieser Aktion wird eine bestehende Wiedervorrätig-Benachrichtigung deaktiviert. **Anwendungsbeispiel**\ Nutzbar auf der Account-Übersichtsseite, auf der eingeloggte Kunden ihre aktiven Benachrichtigungen einsehen und entfernen können. **Parameter** | **Name** | **Beschreibung** | | ----------- | -------------------------------------------------------------------------- | | `productId` | Die ID des Produkts, für das die Benachrichtigung deaktiviert werden soll. | | `email` | Die E-Mail-Adresse, für die die Benachrichtigung deaktiviert werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | ---------------------------- | | `missingProductId` | Parameter `productId` fehlt. | | `missingEmail` | Parameter `email` fehlt. | **Zugehörige Module, Variablen & Methoden** * [\$wsInventory](/frontend/referenz/module/wsinventory) * [\$wsAccount.backInStockList](/frontend/referenz/module/wsAccount#\$wsaccount-backinstocklist) **Beispiel** das zeigt, wie eine aktive Benachrichtigung über einen Button deaktiviert wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionBackInStockDeactivateNotify = $wsActions.create("BackInStockDeactivateNotify") }}
``` # Newsletter Source: https://dokumentation.websale.de/frontend/referenz/aktionen/newsletter Newsletter-Aktionen für Abonnenten: Anmeldung, Double-Opt-In-Bestätigung und Abmeldung vom Newsletter direkt aus dem Frontend ausführen. In diesem Abschnitt werden die verfügbaren Aktionen im Bereich Newsletter beschrieben. Mit diesen Aktionen können Kunden den Newsletter abonnieren, ihre Anmeldung bestätigen und sich wieder abmelden. *** ## Aktionen im Überblick | **Aktion** | **Beschreibung** | | ------------------------------ | ----------------------------------------------------- | | `NewsletterSubscribe` | Meldet einen Kunden für den Newsletter an. | | `NewsletterSubscribeConfirm` | Bestätigt die Newsletter-Anmeldung per Double-Opt-In. | | `NewsletterUnsubscribe` | Meldet einen Kunden vom Newsletter ab. | | `NewsletterUnsubscribeConfirm` | Bestätigt die Newsletter-Abmeldung per Double-Opt-In. | *** ## Aktionen ### NewsletterSubscribe Mit dieser Aktion wird ein Kunde für den Newsletter angemeldet. Nach erfolgreicher Anmeldung erhält der Kunde eine Bestätigungs-E-Mail mit einem Double-Opt-In Link. **Anwendungsbeispiel**\ Nutzbar auf einer Newsletter-Anmeldeseite, auf der Kunden ihre E-Mail-Adresse und optional eine oder mehrere Zielgruppen auswählen können. **Parameter** | **Name** | **Beschreibung** | | -------------------- | ------------------------------------------------------------------- | | `email` | Die E-Mail-Adresse, die für den Newsletter angemeldet werden soll. | | `targetGroupId.(id)` | Optionale Zielgruppen-ID, für die der Kunde angemeldet werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ---------------------- | ------------------------------------------------------------- | | `missingEmail` | Parameter `email` fehlt. | | `emailCheckFailed` | Die angegebene E-Mail-Adresse ist ungültig. | | `accountAlreadyExists` | Die E-Mail-Adresse ist bereits für den Newsletter angemeldet. | **Zugehörige Module, Variablen & Methoden** * [\$wsNewsletter](/frontend/referenz/module/wsnewsletter) * [\$wsNewsletter.getTargetGroups()](/frontend/referenz/module/wsnewsletter#\$wsnewsletter-gettargetgroups) **Beispiel** das zeigt, wie ein Kunde seine E-Mail-Adresse und optional Zielgruppen auswählt, um den Newsletter zu abonnieren, inklusive Erfolgsausgabe nach der Anmeldung. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionNewsletterSubscribe = $wsActions.create("NewsletterSubscribe") }}
{{ if $myActionNewsletterSubscribe.success }}
Newsletter erfolgreich abonniert.
{{ /if }} {{ foreach $myNewsletterList in $wsNewsletter.getTargetGroups() }} {{ /foreach }}
``` *** ### NewsletterSubscribeConfirm Mit dieser Aktion wird die Newsletter-Anmeldung per Double-Opt-In bestätigt. Der Kunde erhält nach der Anmeldung eine E-Mail mit einem Bestätigungslink, über den diese Aktion ausgelöst wird. **Anwendungsbeispiel**\ Nutzbar auf der Bestätigungsseite, auf die der Kunde nach Klick auf den Opt-In-Link in der Anmelde-E-Mail weitergeleitet wird. **Fehlercodes** | **Fehlercode** | **Beschreibung** | | -------------- | ---------------------------------------------- | | `unauthorized` | Es wurde kein gültiger Opt-In-Token übergeben. | **Zugehörige Module, Variablen & Methoden** * [\$wsNewsletter](/frontend/referenz/module/wsnewsletter) **Beispiel** das zeigt, wie nach erfolgreicher Bestätigung eine Erfolgsmeldung angezeigt wird und bei einem ungültigen Token ein Fehlerhinweis erscheint. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionNewsletterSubscribeConfirm = $wsActions.create('NewsletterSubscribeConfirm') }}
{{ if $myActionNewsletterSubscribeConfirm.success }}
Newsletter erfolgreich abonniert.
{{ else }} {{ include "components/errorAlert.htm" with $cAction = $cActionNewsletterSubscribeConfirm }} {{ /if }}
``` *** ### NewsletterUnsubscribe Mit dieser Aktion wird ein Kunde vom Newsletter abgemeldet. Der Kunde gibt dabei seine E-Mail-Adresse an und kann optional einzelne Zielgruppen abwählen. **Anwendungsbeispiel**\ Nutzbar auf der Abmeldeseite, auf der Kunden ihre E-Mail-Adresse eingeben und sich von einzelnen oder allen Newsletter-Zielgruppen abmelden können. **Parameter** | **Name** | **Beschreibung** | | -------------------- | ------------------------------------------------------------------- | | `email` | Die E-Mail-Adresse, die vom Newsletter abgemeldet werden soll. | | `targetGroupId.(id)` | Optionale Zielgruppen-ID, von der der Kunde abgemeldet werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | ------------------------------------------- | | `missingEmail` | Parameter `email` fehlt. | | `emailCheckFailed` | Die angegebene E-Mail-Adresse ist ungültig. | **Zugehörige Module, Variablen & Methoden** * [\$wsNewsletter](/frontend/referenz/module/wsnewsletter) * [\$wsNewsletter.getTargetGroups()](/frontend/referenz/module/wsnewsletter#\$wsnewsletter-gettargetgroups) **Beispiel** das zeigt, wie ein Kunde seine E-Mail-Adresse eingibt und sich von einzelnen Zielgruppen abmeldet, inklusive Erfolgsausgabe. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionNewsletterUnsubscribe = $wsActions.create('NewsletterUnsubscribe') }}
{{ if $cActionNewsletterUnsubscribe.success }}
Erfolgreich vom Newsletter abgemeldet.
{{ else }} {{ foreach $group in $wsNewsletter.getTargetGroups() }} {{ if not $group.deactivated }} {{ /if }} {{ /foreach }} {{ /if }}
``` *** ### NewsletterUnsubscribeConfirm Mit dieser Aktion wird die Newsletter-Abmeldung per Double-Opt-In bestätigt. Der Kunde erhält nach der Abmeldung eine E-Mail mit einem Bestätigungslink, über den diese Aktion ausgelöst wird. **Anwendungsbeispiel**\ Nutzbar auf der Bestätigungsseite, auf die der Kunde nach Klick auf den Opt-In-Link in der Abmelde-E-Mail weitergeleitet wird. **Fehlercodes** | **Fehlercode** | **Beschreibung** | | -------------- | ---------------------------------------------- | | `unauthorized` | Es wurde kein gültiger Opt-In-Token übergeben. | **Zugehörige Module, Variablen & Methoden** * [\$wsNewsletter](/frontend/referenz/module/wsnewsletter) **Beispiel** das zeigt, wie nach erfolgreicher Bestätigung der Abmeldung eine Erfolgsmeldung angezeigt wird und bei einem ungültigen Token ein Fehlerhinweis erscheint. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionNewsletterUnsubscribeConfirm = $wsActions.create('NewsletterUnsubscribeConfirm') }}
{{ if $cActionNewsletterUnsubscribeConfirm.success }}
Erfolgreich vom Newsletter abgemeldet.
{{ else }} {{ /if }}
``` # ProductRating Source: https://dokumentation.websale.de/frontend/referenz/aktionen/productrating ProductRating-Aktionen für Produktbewertungen: Bewertungen durch eingeloggte Kunden erstellen, bearbeiten und wieder löschen lassen. In diesem Abschnitt werden die verfügbaren Aktionen im Bereich Produktbewertungen beschrieben. Mit diesen Aktionen können Bewertungen erstellt, bearbeitet und gelöscht werden. *** ## Aktionen im Überblick | **Aktion** | **Beschreibung** | | --------------------- | -------------------------------------------- | | `ProductRatingAdd` | Erstellt eine neue Produktbewertung. | | `ProductRatingUpdate` | Bearbeitet eine bestehende Produktbewertung. | | `ProductRatingDelete` | Löscht eine bestehende Produktbewertung. | *** ## Aktionen ### ProductRatingAdd Mit dieser Aktion wird eine neue Bewertung für ein Produkt erstellt. Der Kunde muss dafür eingeloggt sein. **Anwendungsbeispiel**\ Nutzbar auf der Produktdetailseite oder in der Bestellhistorie, um eingeloggten Kunden die Möglichkeit zu geben, ein gekauftes Produkt zu bewerten. **Parameter** | **Name** | **Beschreibung** | | ------------- | ------------------------------------------------------- | | `productId` | Die ID des Produkts, das bewertet werden soll. | | `orderId` | Die ID der Bestellung, zu der die Bewertung gehört. | | `points` | Die Bewertung in Punkten (z.B. 1-5 Sterne). | | `subject` | Der Titel der Bewertung. | | `description` | Der Bewertungstext. | | `anonymous` | Gibt an, ob die Bewertung anonym abgegeben werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | --------------------- | ------------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `missingProductId` | Parameter `productId` fehlt. | | `missingOrderId` | Parameter `orderId` fehlt. | | `missingPoints` | Parameter `points` fehlt. | | `ratingAlreadyExists` | Für dieses Produkt und diese Bestellung existiert bereits eine Bewertung. | **Zugehörige Module, Variablen & Methoden** * [\$wsProductRating](/frontend/referenz/module/wsproductrating) * [\$wsProductRating.checkRatingExistence()](/frontend/referenz/module/wsproductrating#\$wsproductrating-checkratingexistence) * [\$wsProductRating.loadAllProductRatings()](/frontend/referenz/module/wsproductrating#\$wsproductrating-loadallproductratings) * [\$wsAccount.isLoggedIn](/frontend/referenz/module/wsAccount#\$wsaccount-isloggedin) **Beispiel** das zeigt, wie ein eingeloggter Kunde ein Produkt mit Sternebewertung, Titel und Kommentar bewerten kann, inklusive Erfolgsausgabe. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionProductRatingAdd = $wsActions.create("ProductRatingAdd") }}
``` *** ### ProductRatingUpdate Mit dieser Aktion wird eine bestehende Produktbewertung des eingeloggten Kunden bearbeitet. **Anwendungsbeispiel**\ Nutzbar auf der Produktdetailseite oder im Kundenkonto, wenn ein Kunde seine abgegebene Bewertung nachträglich anpassen möchte. **Parameter** | **Name** | **Beschreibung** | | ------------- | ------------------------------------------------------------- | | `productId` | Die ID des Produkts, dessen Bewertung bearbeitet werden soll. | | `orderId` | Die ID der Bestellung, zu der die Bewertung gehört. | | `points` | Die neue Bewertung in Punkten. | | `subject` | Der neue Titel der Bewertung. | | `description` | Der neue Bewertungstext. | | `anonymous` | Gibt an, ob die Bewertung anonym abgegeben werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | ---------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `missingProductId` | Parameter `productId` fehlt. | | `missingOrderId` | Parameter `orderId` fehlt. | | `invalidRating` | Die Bewertung existiert nicht oder gehört nicht zu diesem Kundenkonto. | **Zugehörige Module, Variablen & Methoden** * [\$wsProductRating](/frontend/referenz/aktionen/productrating) * [\$wsProductRating.loadSingleRating()](/frontend/referenz/module/wsproductrating#\$wsproductrating-loadsinglerating) * [\$wsProductRating.loadRatingByAccount()](/frontend/referenz/module/wsproductrating#\$wsproductrating-loadratingbyaccount) * [\$wsAccount.isLoggedIn](/frontend/referenz/module/wsAccount#\$wsaccount-isloggedin) **Beispiel** das zeigt, wie ein Kunde eine bestehende Bewertung bearbeiten kann, mit vorausgefüllten Feldern. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionProductRatingUpdate = $wsActions.create("ProductRatingUpdate") }} {{ var $myRating = $wsProductRating.loadSingleRating($myProduct, $myOrderId) }}
``` *** ### ProductRatingDelete Mit dieser Aktion wird eine bestehende Produktbewertung des eingeloggten Kunden gelöscht. **Anwendungsbeispiel**\ Nutzbar auf der Produktdetailseite oder im Kundenkonto, wenn ein Kunde seine abgegebene Bewertung entfernen möchte. **Parameter** | **Name** | **Beschreibung** | | ----------- | ----------------------------------------------------------- | | `productId` | Die ID des Produkts, dessen Bewertung gelöscht werden soll. | | `orderId` | Die ID der Bestellung, zu der die Bewertung gehört. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | ---------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `missingProductId` | Parameter `productId` fehlt. | | `missingOrderId` | Parameter `orderId` fehlt. | | `invalidRating` | Die Bewertung existiert nicht oder gehört nicht zu diesem Kundenkonto. | **Zugehörige Module, Variablen & Methoden** * [\$wsProductRating](/frontend/referenz/aktionen/productrating) * [\$wsProductRating.loadRatingByAccount()](/frontend/referenz/module/wsproductrating#\$wsproductrating-loadratingbyaccount) * [\$wsAccount.isLoggedIn](/frontend/referenz/module/wsAccount#\$wsaccount-isloggedin) **Beispiel** das zeigt, wie eine Bewertung über einen Button gelöscht wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionProductRatingDelete = $wsActions.create("ProductRatingDelete") }}
``` # Session Source: https://dokumentation.websale.de/frontend/referenz/aktionen/session Session-Aktionen im Frontend: eigene Session-Variablen schreiben und nach fehlgeschlagenem Bezahlvorgang eine gesperrte Session entsperren. In diesem Abschnitt werden die verfügbaren Aktionen der Session beschrieben. Mit diesen Aktionen können z.B. Session-Variablen geschrieben oder eine gesperrte Session nach einem fehlgeschlagenen Bezahlvorgang wieder entsperrt werden. *** ## Aktionen im Überblick | **Aktion** | **Beschreibung** | | --------------- | ----------------------------------------------------------------------- | | `SessionUpdate` | Schreibt einen Wert in eine Session-Variable. | | `SessionUnlock` | Entsperrt die Session nach einem fehlgeschlagenen Online-Bezahlvorgang. | *** ## Aktionen ### SessionUpdate Mit dieser Aktion wird ein Wert in eine Session-Variable geschrieben. Die Variable wird dabei über den Parameternamen `session.(variableName)` adressiert, wobei `variableName` für den gewünschten Schlüssel innerhalb der Session steht. **Anwendungsbeispiel**\ Nutzbar, um während des Nutzererlebnisses benutzerdefinierte Zustandsinformationen in der Session zu speichern, z.B. einen ausgewählten Filter, einen Fortschritt im Checkout oder einen temporären Hinweis, der seitenübergreifend verfügbar sein soll. **Parameter** | **Name** | **Beschreibung** | | ------------------------ | --------------------------------------------------------------------- | | `session.(variableName)` | Der Schlüssel und Wert der Session-Variable, die gesetzt werden soll. | **Zugehörige Module, Variablen & Methoden** * [\$wsSession](/frontend/referenz/module/wssession) * [\$wsSession.set()](/frontend/referenz/module/wssession#\$wssession-set) * [\$wsSession.get()](/frontend/referenz/module/wssession#\$wssession-get) **Beispiel** das zeigt, wie ein Wert in eine Session-Variable geschrieben und anschließend ausgelesen wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionSessionUpdate = $wsActions.create("SessionUpdate") }}
{{ if $wsSession.get("lastViewedCategory") }} Kategorie: {{= $wsSession.get("lastViewedCategory") }} {{ /if }} ``` *** ### SessionUnlock Mit dieser Aktion wird eine gesperrte Session wieder entsperrt. Eine Session kann nach einem fehlgeschlagenen Online-Bezahlvorgang in einen gesperrten Zustand geraten, um unbeabsichtigte Folgeaktionen zu verhindern. `SessionUnlock` setzt diesen Sperrzustand zurück, sodass der Kunde den Vorgang erneut starten oder fortsetzen kann. Diese Aktion erwartet keine Parameter und liefert keine Fehlerrückmeldungen. **Anwendungsbeispiel**\ Nutzbar auf einer Fehler- oder Rücksprungs-Seite nach einem fehlgeschlagenen Zahlungsvorgang, um dem Kunden zu ermöglichen, die Zahlung erneut zu versuchen oder eine andere Zahlungsmethode auszuwählen. **Zugehörige Module, Variablen & Methoden** * [\$wsSession](/frontend/referenz/module/wssession) * [\$wsSession.isLocked](/frontend/referenz/module/wssession#\$wssession-islocked) **Beispiel** das zeigt, wie einem Kunden bei gesperrter Session die Möglichkeit gegeben wird, diese über einen Button zu entsperren. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsSession.isLocked }} {{ var $myActionSessionUnlock = $wsActions.create("SessionUnlock") }}
{{ /if }} ``` # Stores Source: https://dokumentation.websale.de/frontend/referenz/aktionen/stores Stores-Aktionen für Märkte und Filialen: Markt für aktuelle Session oder den Checkout-Prozess setzen, ändern und für Click & Collect nutzen. In diesem Abschnitt werden die verfügbaren Aktionen im Bereich Märkte (Stores) beschrieben. Mit diesen Aktionen kann z.B. ein Markt für die aktuelle Session oder den Checkout-Prozess ausgewählt werden. *** ## Aktionen im Überblick | **Aktion** | **Beschreibung** | | ------------- | ------------------------------------------------------------- | | `SelectStore` | Setzt einen Markt als aktiven Markt für die aktuelle Session. | *** ## Aktionen ### SelectStore Mit dieser Aktion wählt der Kunde einen Markt als seinen aktiven Markt für die aktuelle Session aus. Die Auswahl wird sofort übernommen und steht anschließend z.B. für die Anzeige von standortbezogenen Inhalten oder als Vorauswahl im Checkout zur Verfügung. **Anwendungsbeispiel**\ Nutzbar, um z.B. auf einer Markt-Übersichtsseite, auf der dem Kunden alle verfügbaren Märkte angezeigt werden und er per Klick seinen gewünschten Markt auswählen kann, z.B. um Öffnungszeiten, Verfügbarkeiten oder Click & Collect-Optionen für seinen Markt zu sehen. **Parameter** | **Name** | **Beschreibung** | | --------- | -------------------------------------------------------------- | | `storeId` | Die ID des Marktes, der als aktiver Markt gesetzt werden soll. | **Fehlercodes** | **Code** | **Beschreibung** | | ---------------- | ---------------------------------------------------------- | | `missingStoreId` | Parameter `storeId` fehlt. | | `invalidStoreId` | Die angegebene Markt-ID existiert nicht oder ist ungültig. | **Zugehörige Module, Variablen & Methoden** * [\$wsStores](/frontend/referenz/module/wsstores) * [\$wsStores.loadAllStores()](/frontend/referenz/module/wsstores#\$wsstores-loadallstores) * [\$wsStores.selectedStore](/frontend/referenz/module/wsstores#\$wsstores-selectedstore) **Beispiel** das zeigt, wie alle verfügbaren Märkte als Auswahlliste dargestellt werden und der aktuell ausgewählte Markt vorausgewählt ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionSelectStore = $wsActions.create("SelectStore") }}
{{ foreach $myStore in $wsStores.loadAllStores() }} {{ /foreach }}
``` # TestMode Source: https://dokumentation.websale.de/frontend/referenz/aktionen/testmode TestMode-Aktionen: Testmodus im Frontend aktivieren, deaktivieren und zwischen Test- und Live-Modus wechseln, ohne Live-Betrieb zu beeinflussen. In diesem Abschnitt werden die verfügbaren Aktionen im Bereich Testmodus beschrieben. Mithilfe dieser Aktionen kann der Testmodus aktiviert, deaktiviert und gewechselt werden. Beim Aktivieren können Sie außerdem das erweiterte Debugging einschalten und fehlgeschlagene Zahlungen simulieren. *** ## Aktionen im Überblick | **Aktion** | **Beschreibung** | | ---------------- | ------------------------------------------------------------------------------------------- | | `TestModeOn` | Aktiviert den Testmodus, optional mit Debugging und simulierten fehlgeschlagenen Zahlungen. | | `TestModeOff` | Deaktiviert den Testmodus. | | `TestModeChange` | Wechselt den aktiven Testmodus. | *** ## Aktionen ### TestModeOn Mit dieser Aktion wird der Testmodus aktiviert. Der Benutzer muss dafür das konfigurierte Testmodus-Passwort angeben. Mit dem Parameter `makePaymentFail` werden Zahlungen im Testmodus zusätzlich als fehlgeschlagen simuliert. Dadurch laufen Bestellungen gezielt in den Fehlerfall, sodass die dafür vorgesehenen Templates und Abläufe geprüft werden können. Die aktuelle Konfiguration kann im Template über \$wsTestMode abfragt werden. **Anwendungsbeispiel**\ Nutzbar auf der Testmodus Seite (`testMode.htm`), über die Shopbetreiber oder Tester den Testmodus mit einem Passwort aktivieren können, um testspezifische Inhalte zu sehen. **Parameter** | **Name** | **Beschreibung** | | ----------------- | ------------------------------------------------------------------- | | `password` | Das Passwort zur Aktivierung des Testmodus. | | `debug` | Aktiviert das erweiterte Debugging (Wert: “`on`”). | | `makePaymentFail` | Simuliert Zahlungen im Testmodus als fehlgeschlagen (Wert: “`on`”). | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ----------------- | ----------------------------------- | | `missingPassword` | Parameter `password` fehlt. | | `invalidPassword` | Das angegebene Passwort ist falsch. | **Zugehörige Module, Variablen & Methoden** * [\$wsTestMode](/frontend/referenz/module/wstestmode) * [\$wsTestMode.active](/frontend/referenz/module/wstestmode#\$wstestmode-active) * [\$wsTestMode.debug](/frontend/referenz/module/wstestmode#\$wstestmode-debug) * [\$wsTestMode.makePaymentFail](/frontend/referenz/module/wstestmode#\$wstestmode-makepaymentfail) **Beispiel** das zeigt, wie der Testmodus über ein Passwortformular aktiviert wird, optional mit Debugging und simulierten fehlgeschlagenen Zahlungen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cActionTestModeOn = $wsActions.create("TestModeOn") }}
``` *** ### TestModeOff Mit dieser Aktion wird der Testmodus deaktiviert und der Shop kehrt in den normalen Live-Betrieb zurück. **Anwendungsbeispiel**\ Nutzbar auf der Testmodus-Seite oder im Shop-Header, um den Testmodus direkt im Shop zu deaktivieren. **Zugehörige Module, Variablen & Methoden** * [\$wsTestMode](/frontend/referenz/module/wstestmode) * [\$wsTestMode.active](/frontend/referenz/module/wstestmode#\$wstestmode-active) **Beispiel** das zeigt, wie der Testmodus über einen Button deaktiviert wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionTestModeOff = $wsActions.create("TestModeOff") }}
``` *** ### TestModeChange Mit dieser Aktion wird der aktive Testmodus gewechselt, ohne ihn komplett zu deaktivieren. Dies ist nützlich, wenn mehrere Testmodi konfiguriert sind. **Anwendungsbeispiel**\ Nutzbar auf der Testmodus-Seite, wenn verschiedene Testszenarien oder Konfigurationen parallel verfügbar sind und zwischen diesen gewechselt werden soll. **Parameter** | **Name** | **Beschreibung** | | -------- | ------------------------------------------------------------------- | | `debug` | Aktiviert oder deaktiviert das erweiterte Debugging (Wert: “`on`”). | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ----------------- | ----------------------------------- | | `invalidPassword` | Das angegebene Passwort ist falsch. | **Zugehörige Module, Variablen & Methoden** * [\$wsTestMode](/frontend/referenz/module/wstestmode) * [\$wsTestMode.active](/frontend/referenz/module/wstestmode#\$wstestmode-active) * [\$wsTestMode.debug](/frontend/referenz/module/wstestmode#\$wstestmode-debug) **Beispiel** das zeigt, wie die Debug-Einstellung des aktiven Testmodus geändert wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionTestModeChange = $wsActions.create("TestModeChange") }}
``` # Voucher Source: https://dokumentation.websale.de/frontend/referenz/aktionen/voucher Voucher-Aktionen im Warenkorb: Gutscheincodes mit VoucherAdd einlösen und über VoucherDelete wieder aus dem aktuellen Warenkorb entfernen. In diesem Abschnitt werden die verfügbaren Aktionen im Bereich Gutscheine beschrieben. Mit diesen Aktionen können Gutscheincodes im Warenkorb eingelöst und wieder entfernt werden. *** ## Aktionen im Überblick | **Aktion** | **Beschreibung** | | --------------- | ------------------------------------------------------- | | `VoucherAdd` | Löst einen Gutscheincode im Warenkorb ein. | | `VoucherDelete` | Entfernt einen eingelösten Gutschein aus dem Warenkorb. | *** ## Aktionen ### VoucherAdd Mit dieser Aktion wird ein Gutscheincode im Warenkorb eingelöst. **Anwendungsbeispiel**\ Nutzbar auf der Warenkorbseite oder im Warenkorb-Offcanvas, wo Kunden einen Gutscheincode eingeben und direkt auf ihre Bestellung anwenden können. **Parameter** | **Name** | **Beschreibung** | | -------- | --------------------------------------------- | | `id` | Der Gutscheincode, der eingelöst werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ---------------- | ----------------------------------------------------------------- | | `missingId` | Parameter `id` fehlt. | | `invalidVoucher` | Der angegebene Gutscheincode ist ungültig oder bereits eingelöst. | **Zugehörige Module, Variablen & Methoden** * [\$wsVoucher](/frontend/referenz/module/wsvoucher) * [\$wsVoucher.vouchers](/frontend/referenz/module/wsvoucher#\$wsvoucher-vouchers) * [\$wsVoucher.totalValue](/frontend/referenz/module/wsvoucher#\$wsvoucher-totalvalue) **Beispiel** das zeigt, wie ein Gutscheincode über ein Eingabefeld eingelöst wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionVoucherAdd = $wsActions.create("VoucherAdd") }}
``` *** ### VoucherDelete Mit dieser Aktion wird ein bereits eingelöster Gutschein aus dem Warenkorb entfernt. **Anwendungsbeispiel**\ Nutzbar auf der Warenkorbseite oder im Warenkorb-Offcanvas, wenn Kunden einen eingelösten Gutschein wieder entfernen möchten. **Parameter** | **Name** | **Beschreibung** | | -------- | ------------------------------------------------ | | `id` | Die ID des Gutscheins, der entfernt werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | ------------------------------------------------------------------------------- | | `missingId` | Parameter `id` fehlt. | | `invalidVoucherId` | Der angegebene Gutschein existiert nicht oder gehört nicht zu diesem Warenkorb. | **Zugehörige Module, Variablen & Methoden** * [\$wsVoucher](/frontend/referenz/module/wsvoucher) * [\$wsVoucher.vouchers](/frontend/referenz/module/wsvoucher#\$wsvoucher-vouchers) * [\$wsVoucher.totalValue](/frontend/referenz/module/wsvoucher#\$wsvoucher-totalvalue) **Beispiel** das zeigt, wie alle eingelösten Gutscheine aufgelistet werden und jeder einzelne über einen Button entfernt werden kann. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $myVoucher in $wsVoucher.vouchers }} {{ var $myActionVoucherDelete = $wsActions.create("VoucherDelete") }}
{{ /foreach }} ``` # WatchList Source: https://dokumentation.websale.de/frontend/referenz/aktionen/watchlist WatchList-Aktionen für die Merkliste: Produkte über WatchListItemAdd hinzufügen und über WatchListItemDelete aus der Wunschliste entfernen. In diesem Abschnitt werden die verfügbaren Aktionen im Bereich Merkliste beschrieben. Mit diesen Aktionen können Produkte zur Merkliste hinzugefügt oder daraus entfernt werden. *** ## Aktionen im Überblick | **Aktion** | **Beschreibung** | | --------------------- | --------------------------------------------------- | | `WatchListItemAdd` | Fügt ein oder mehrere Produkte zur Merkliste hinzu. | | `WatchListItemDelete` | Entfernt ein Produkt aus der Merkliste. | | `AddWatchList` | Erstellt eine neue Merkliste. | | `DeleteWatchList` | Löscht eine bestehende Merkliste. | | `RenameWatchList` | Benennt eine bestehende Merkliste um. | *** ## Aktionen ### WatchListItemAdd Mit dieser Aktion wird ein Produkt zur Merkliste des Benutzers hinzugefügt. Es können sowohl einzelne Produkte als auch mehrere Produkte gleichzeitig übergeben werden. **Anwendungsbeispiel**\ Nutzbar auf Produkt- oder Kategorieseiten, auf denen Kunden Artikel auf ihre Merkliste setzen können, um sie später wiederzufinden oder zu kaufen. **Parameter** | **Name** | **Beschreibung** | | -------------------------------------- | ------------------------------------------------------------------------------- | | `productId` | Die ID des Produkts, das zur Merkliste hinzugefügt werden soll. | | `freeFields.` | Optionale Freifelder, die dem Merklisten-Eintrag zugeordnet werden können. | | `multiProducts..` | Ermöglicht das gleichzeitige Hinzufügen mehrerer Produkte mit jeweiliger Menge. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------ | ----------------------------------------------------------------------- | | `missingProductId` | Parameter `productId` fehlt oder ist leer. | | `invalidProductId` | Das Produkt mit der angegebenen `productId` existiert nicht. | | `invalidVariantId` | Die angegebene Variante des Produkts ist ungültig oder nicht vorhanden. | **Zugehörige Module, Variablen & Methoden** * [\$wsWatchList](/frontend/referenz/module/wswatchlist) * [\$wsWatchList.watchLists](/frontend/referenz/module/wswatchlist#\$wswatchlist-watchlists) * [\$wsWatchList.loadWatchList()](/frontend/referenz/module/wswatchlist#\$wswatchlist-loadwatchlist) * [\$wsWatchList.isProductOnWatchList()](/frontend/referenz/module/wswatchlist#\$wswatchlist-isproductonwatchlist) * [\$wsWatchList.countWatchListsWithProduct()](/frontend/referenz/module/wswatchlist#\$wswatchlist-countwatchlistswithproduct) **Beispiel** das zeigt, wie ein Produkt zur Standard-Merkliste hinzugefügt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionWatchListItemAdd = $wsActions.create("WatchListItemAdd") }}
``` *** ### WatchListItemDelete Mit dieser Aktion wird ein Eintrag aus der Merkliste des Benutzers entfernt. **Anwendungsbeispiel**\ Nutzbar auf der Merklisten-Seite, auf der Kunden einzelne Produkte wieder von ihrer Merkliste löschen können. **Parameter** | **Name** | **Beschreibung** | | ----------------- | --------------------------------------------------------- | | `watchListItemId` | Die ID des Merklisten-Eintrags, der gelöscht werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ------------------------ | ------------------------------------------------ | | `missingWatchListItemId` | Parameter `watchListItemId` fehlt oder ist leer. | **Zugehörige Module, Variablen & Methoden** * [\$wsWatchList](/frontend/referenz/module/wswatchlist) * [\$wsWatchList.watchLists](/frontend/referenz/module/wswatchlist#\$wswatchlist-watchlists) * [\$wsWatchList.loadWatchList()](/frontend/referenz/module/wswatchlist#\$wswatchlist-loadwatchlist) * [\$wsWatchList.loadWatchListItemId()](/frontend/referenz/module/wswatchlist#\$wswatchlist-loadwatchlistitemid) **Beispiel** das zeigt, wie ein Produkt anhand seiner Merklisten-Eintrags-ID aus der Standard-Merkliste entfernt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionWatchListItemDelete = $wsActions.create("WatchListItemDelete") }} {{ var $myWatchListItemId = $wsWatchList.loadWatchListItemId("default", $myProduct.id) }}
``` *** ### AddWatchList Mit dieser Aktion wird eine neue Merkliste für den eingeloggten Benutzer erstellt. **Anwendungsbeispiel**\ Nutzbar auf der Merklisten-Verwaltungsseite, auf der Kunden zusätzlich Merklisten anlegen können, z.B. für verschiedene Anlässe oder Kategorien. **Parameter** | **Name** | **Beschreibung** | | --------------- | ----------------------------- | | `watchListName` | Der Name der neuen Merkliste. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ---------------------- | ---------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `missingWatchListName` | Parameter `watchListName` fehlt. | **Zugehörige Module, Variablen & Methoden** * [\$wsWatchList](/frontend/referenz/module/wswatchlist) * [\$wsWatchList.watchLists](/frontend/referenz/module/wswatchlist#\$wswatchlist-watchlists) **Beispiel** das zeigt, wie eine neue Merkliste über ein Eingabefeld erstellt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionAddWatchList = $wsActions.create("AddWatchList") }}
``` *** ### DeleteWatchList Mit dieser Aktion wird eine bestehende Merkliste des eingeloggten Benutzers gelöscht. **Anwendungsbeispiel**\ Nutzbar auf der Merklisten-Verwaltungsseite, auf der Kunden nicht mehr benötigte Merklisten entfernen können. **Parameter** | **Name** | **Beschreibung** | | ------------- | ----------------------------------------------- | | `watchListId` | Die ID der Merkliste, die gelöscht werden soll. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | -------------------- | ----------------------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `missingWatchListId` | Parameter `watchListId` fehlt. | | `invalidWatchListId` | Die angegebene Merkliste existiert nicht oder gehört nicht zu diesem Benutzerkonto. | **Zugehörige Module, Variablen & Methoden** * [\$wsWatchList](/frontend/referenz/module/wswatchlist) * [\$wsWatchList.watchLists](/frontend/referenz/module/wswatchlist#\$wswatchlist-watchlists) **Beispiel** das zeigt, wie eine Merkliste über einen Button gelöscht wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionDeleteWatchList = $wsActions.create("DeleteWatchList") }}
``` *** ### RenameWatchList Mit dieser Aktion wird eine bestehende Merkliste des eingeloggten Benutzers umbenannt. **Anwendungsbeispiel**\ Nutzbar auf der Merklisten-Verwaltungsseite, auf der Kunden den Namen einer bestehenden Merkliste anpassen können. **Parameter** | **Name** | **Beschreibung** | | --------------- | ------------------------------------------------ | | `watchListId` | Die ID der Merkliste, die umbenannt werden soll. | | `watchListName` | Der neue Name der Merkliste. | **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ---------------------- | ----------------------------------------------------------------------------------- | | `notLoggedIn` | Der Benutzer ist nicht eingeloggt. | | `missingWatchListId` | Parameter `watchListId` fehlt. | | `missingWatchListName` | Parameter `watchListName` fehlt. | | `invalidWatchListId` | Die angegebene Merkliste existiert nicht oder gehört nicht zu diesem Benutzerkonto. | **Zugehörige Module, Variablen & Methoden** * [\$wsWatchList](/frontend/referenz/module/wswatchlist) * [\$wsWatchList.watchLists](/frontend/referenz/module/wswatchlist#\$wswatchlist-watchlists) **Beispiel** das zeigt, wie eine Merkliste über ein Eingabefeld umbenannt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myActionRenameWatchList = $wsActions.create("RenameWatchList") }}
``` # Anweisungen und Ausgabe Source: https://dokumentation.websale.de/frontend/referenz/anweisungen Anweisungen und Ausgabe in Templates: Syntax für Verarbeitung, Ausgabe und automatisches Escaping verstehen und kontextsicher einsetzen. Beim Erstellen von Templates reicht es nicht aus, nur [Variablen](/frontend/referenz/variablen), [Funktionen ](/frontend/referenz/funktionen)oder [Operatoren ](/frontend/referenz/operatoren)zu kennen. Ebenso wichtig ist es, wie ein Ausdruck im Template verarbeitet wird. Die verwendete Syntax entscheidet darüber, ob eine Anweisung nur ausgeführt, ein Wert ausgegeben oder eine Ausgabe automatisch escaped wird. Diese Unterscheidung ist für die Template-Entwicklung relevant, weil sie direkten Einfluss auf das erzeugte Ergebnis hat. Je nach Schreibweise erscheint ein Wert im HTML, wird nur intern verarbeitet oder unverändert ausgegeben. Dadurch bestimmt die Syntax nicht nur die Ausgabe selbst, sondern auch, ob Inhalte für den jeweiligen Kontext korrekt und sicher ausgegeben werden. Die verschiedenen Formen von Anweisungen helfen daher dabei, Template-Logik und Ausgabe sauber zu steuern. Sie legen fest, wann ein Ausdruck lediglich verarbeitet wird und wann sein Ergebnis im generierten Dokument erscheint. Gleichzeitig steuern sie das Escaping und damit den Umgang mit Sonderzeichen, HTML-Inhalten oder anderen Ausgabekontexten. Diese Seite beschreibt die verfügbaren Schreibweisen für Anweisungen und zeigt, wie sie sich auf Verarbeitung, Ausgabe und Escaping auswirken. *** ## Anweisungen im Überblick | **Syntax** | **Beschreibung** | Typische Verwendung | | --------------------------------------------------- | --------------------------------------------------------- | --------------------------------------------------------------- | | `{{ ... }}` | Führt eine Anweisung aus, ohne eine Ausgabe zu erzeugen. | Variablen setzen, Hilfslogik ausführen. | | `{{= … }}` | Gibt einen Wert aus und ersetzt dabei HTML-Sonderzeichen. | Normale Ausgabe im HTML. | | `{{! … !}}` | Gibt einen Wert aus, ohne HTML-Sonderzeichen zu ersetzen. | Bereits aufbereitete Inhalte gezielt unverändert
ausgeben. | | `{{ autoescape “js” }} … `
`{{ /autoescape }}` | Wechselt den Escaping-Modus innerhalb eines Blocks. | Ausgabe in speziellen Kontexten, z.B. JavaScript | ## Anweisungen ohne Ausgabe Mit `{{ ... }}` wird eine Anweisung ausgeführt, ohne dass ihr Ergebnis direkt ausgegeben wird. Diese Schreibweise wird verwendet, wenn im Template etwas vorbereitet oder verarbeitet werden soll, ohne dass an dieser Stelle bereits Inhalt im generierten Dokument bzw. Seite erscheint. Typische Anwendungsfälle sind das Setzen von Variablen, das Vorbereiten von Hilfswerten oder das Aufrufen von Logik, deren Ergebnis erst später benötigt wird. ### **Beispiel** In diesem Beispiel wird der Produktname in einer Variablen gespeichert. An dieser Stelle wird jedoch noch nichts ausgegeben. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myVariableForProductname = $product.name }} ``` ### Verwendung Diese Syntax ist sinnvoll, wenn ein Wert zunächst nur weiterverarbeitet oder für eine spätere Ausgabe vorbereitet werden soll. Sie sollte verwendet werden, wenn: * eine Variable gesetzt wird * ein Wert zwischengespeichert wird * eine Anweisung nur der Template-Logik dient * an dieser Stelle keine direkte Ausgabe im HTML gewünscht ist *** ## Ausgabe mit Escaping Mit `{{= … }}` wird ein Wert ausgegeben und dabei automatisch escaped. Diese Schreibweise ist der Standard für die Ausgabe im Template, wenn Inhalte im HTML erscheinen sollen. Einfache `(')` und doppelte `(")` Anführungszeichen innerhalb von `{{= … }}` sind gleichwertig. Der Unterschied wirkt sich nur auf das Syntax-Highlighting im Code-Editor aus. Escaping sorgt dafür, dass Sonderzeichen nicht als HTML interpretiert werden. Dadurch bleibt die Ausgabe korrekt und Inhalte werden als Text behandelt. ### Beispiel ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $product.name }} ``` Enthält `$product.name` beispielsweise den Wert ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Tom & Jerry ``` wird daraus in der HTML-Ausgabe ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} <b>Tom & Jerry</b> ``` Die Zeichen werden also so ausgegeben, dass sie im Browser korrekt dargestellt werden und nicht als HTML-Markup interpretiert werden. ### Verwendung Diese Syntax sollte für normale Ausgaben im Template grundsätzlich bevorzugt werden. Sie sollte verwendet werden, wenn: * Text im HTML ausgegeben werden soll * Inhalte aus Variablen ausgegeben werden * nicht ausdrücklich gewünscht ist, dass HTML unverändert übernommen wird * eine sichere Standardausgabe benötigt wird In der Praxis ist `{{= … }}` in den meisten Fällen die richtige Wahl. *** ## Escaping für einen Bereich festlegen Mit `autoescape` kann für einen zusammenhängenden Bereich festgelegt werden, wie Ausgaben escaped werden sollen. Das ist vor allem dann relevant, wenn Inhalte nicht im normalen HTML-Kontext ausgegeben werden, sondern beispielsweise innerhalb von JavaScript. ### Beispiel ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ autoescape "js" }} const productName = "{{= $product.name }}"; {{ /autoescape }} ``` In diesem Beispiel wird der Escaping-Modus für JavaScript gesetzt. Dadurch werden Ausgaben innerhalb dieses Bereichs passend für diesen Kontext behandelt. Enthält `$product.name` zum Beispiel den Wert `Damen-Jacke "Alpine"` , wird daraus `"Damen-Jacke \"Alpine\"` , sodass die Anführungszeichen den JavaScript-String nicht unterbrechen. ### Verwendung Diese Syntax sollte verwendet werden, wenn die Ausgabe in einem speziellen Ausgabekontext erfolgt, für den ein anderer Escaping-Modus erforderlich ist. Das ist insbesondere sinnvoll, wenn Inhalte innerhalb von JavaScript, JSON oder vergleichbaren Kontexten ausgegeben werden. *** ## Ausgabe ohne Escaping Mit `{{! … !}}` wird ein Wert unverändert ausgegeben. Es erfolgt kein automatisches Escaping. Die Ausgabe wird also genau so in das generierte Dokument übernommen, wie der Wert vorliegt. Das ist nur dann sinnvoll, wenn der Inhalt bewusst ungeescaped ausgegeben werden soll, etwa weil er bereits korrekt als HTML formatiert wurde. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{! $product.name !}} ``` Enthält `$product.name` beispielsweise den Wert ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Tom & Jerry ``` wird dieser Inhalt in der HTML-Ausgabe auch als HTML übernommen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Tom & Jerry ``` ### Verwendung Diese Syntax sollte nur gezielt und mit Vorsicht verwendet werden. Sie sollte verwendet werden, wenn: * Inhalte bewusst als HTML ausgegeben werden sollen * der auszugebende Wert bereits korrekt aufbereitet ist * kein zusätzliches Escaping mehr erfolgen darf Sie sollte nicht verwendet werden, wenn gewöhnlicher Text ausgegeben werden soll. In solchen Fällen ist `{{= … }}` die richtige Wahl. # Blöcke Source: https://dokumentation.websale.de/frontend/referenz/blocke Blöcke als Grundstruktur von Templates: Header, Footer und Navigation in benannte Bereiche teilen und unabhängig erweitern oder überschreiben. Blöcke bilden die grundlegende Struktur eines [Templates](/frontend/die-basics/template-theme) und ermöglichen eine flexible Anpassung der Storefront. Sie unterteilen das Layout in klar benannte, isolierte Bereiche wie Header, Footer oder Navigation, die unabhängig voneinander angepasst werden können. Diese Seite behandelt alles, was es über Blöcke im Detail zu wissen gibt: was sie können, was sie nicht können und wie man sie sinnvoll einsetzt. ## Grundprinzip Blöcke bauen auf dem Zusammenspiel von Basis- und View-Templates auf. Das [Basis-Template](/frontend/die-basics/template-theme#2-basis-template-layout-template) definiert das übergeordnete Seitenlayout mit allem, was auf jeder Seite gleich bleibt - wie Header, Footer, Navigation oder eingebundene Skripte. Das [View-Template](/frontend/die-basics/template-theme#4-view-templates-seiten-templates) ist das Template einer konkreten Seite - es bindet das Basis Template per `{{ extends }}` ein und befüllt einzelne Bereiche mit seitenspezifischem Inhalt. Ein Block ist ein benannter Bereich innerhalb eines Templates, der durch `{{ block “name” }}` geöffnet und durch `{{ /block }}` geschlossen wird. Er ist sowohl ein Struktur- als auch ein Inhaltsbaustein. Im Basis-Template legt er fest, welche Bereiche eine Seite hat und wo sie sich befinden, inklusive eines Standardinhalts, der angezeigt wird, solange ein View-Template diesen Block nicht explizit überschreibt. Im View-Template füllt er genau diese Bereiche mit seitenspezifischem Inhalt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ block "header" }}

Standard-Header

{{ /block }} ``` *** ## Blöcke überschreiben Ein View-Template greift einen Block auf, indem es ihn mit demselben Namen erneut definiert. Dabei gibt es drei Möglichkeiten: 1. Der Standardinhalt wird vollständig ersetzt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ extends "layouts/default.htm" }} {{ block "header" }}

Willkommen im Shop!

{{ /block }} ``` 2. Mit `append` - der neue Inhalt wird hinter dem Standardinhalt eingefügt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ block "header" append }}

Versandkostenfreiheit ab 50 €

{{ /block }} ``` 3. Mit `prepend` - der neue Inhalt wird vor dem Standardinhalt eingefügt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ block "header" prepend }}

Kostenloser Versand heute!

{{ /block }} ``` Der Basis-Block bleibt in allen Fällen unverändert. `append` und `prepend`sind praktisch, wenn der Standardinhalt eines Blocks grundsätzlich passt, aber auf einzelnen Seiten um zusätzliche Inhalte ergänzt werden soll. *** ## Verwendung von Blöcken in Templates Blöcke können nicht in jedem Template-Typ definiert oder überschrieben werden. Es kommt darauf an, welche Rolle ein Template im System übernimmt: * **Basis-Templates** (Layout-Templates) sind der einzige Ort, an dem Blöcke definiert werden. Sie legen fest, welche Bereiche einer Seite existieren und welche Standardinhalte diese haben. * **View-Templates** (Seiten-Templates) und **E-Mail-Templates** können Blöcke eines Basis-Templates überschreiben oder erweitern. Beide binden ein Basis-Template per `{{ extends }}` ein. Dabei gilt eine wichtige Einschränkung: Ein Template mit `{{ extends }}` darf ausschließlich aus Blockanweisungen bestehen. Kein HTML, kein Code, kein Include darf außerhalb eines Blocks stehen. Typische Blöcke, die das Standard-Layout bereitstellt: | **Block** | **Typischer Inhalt** | | -------------- | ------------------------ | | `header` | Kopfbereich der Seite | | `content_main` | Hauptinhalt der Seite | | `footer` | Fußbereich der Seite | | `scripts` | JavaScript am Seitenende | *** ## Blöcke und andere Konstrukte Im Template-System gibt es mehrere Möglichkeiten, Code zu strukturieren und wiederzuverwenden. Blöcke sind dabei nur eines von mehreren Werkzeugen. Blöcke reservieren benannte Platzhalter im Layout, die ein View-Template später mit seitenspezifischem Inhalt füllen kann. Sie funktionieren von oben nach unten - das Basis-Template gibt den Rahmen vor, das View-Template füllt ihn. Blöcke sind das Bindeglied zwischen Layout und Seiteninhalt. [Includes](/frontend/die-basics/template-theme#5-components-includes) binden eine separate Template-Datei an einer bestimmten Stelle ein - ähnlich wie ein Baustein, der an mehreren Stellen eingesetzt werden kann. Ein Breadcrumb oder eine Fehlermeldung sind typische Beispiele - der Code wird einmal geschrieben und überall dort eingebunden, wo er gebraucht wird. Anders als Blöcke können Includes Variablen entgegennehmen und sind damit flexibel in ihren Parametern. [Module](/frontend/referenz/module) wie `$wsBasket` oder `$wsProducts` stellen Daten bereit. Sie sind keine Template-Bausteine sondern serverseitige Datenquellen, auf die man im Template zugreift. In der Praxis greifen alle drei ineinander. Ein Block definiert den Bereich der Seite, innerhalb des Blocks werden Includes eingebunden - diese greifen über Module auf die benötigten Daten zu. *** ## Erlaubter Inhalt ### HTML und Template-Syntax Innerhalb eines Blocks sind erlaubt: * Beliebiges HTML * Variablendeklarationen (`{{ var ... }}`) und Ausgaben (`{{= ... }}`) * Kontrollstrukturen wie `{{ if }}`, `{{ foreach }}`, `{{ switch }}` * Includes (`{{ include ... }}`) * Modulzugriffe (`$wsBasket.items`, `$wsCheckout.sum.total` etc.) ### JavaScript und CSS Blöcke wie `head` oder `scripts` können ohne Einschränkungen ` {{ /if }} {{ /block }} ``` ### Block, der einen anderen Block enthält Im Basis-Template können Blöcke ineinander verschachtelt werden. Jeder innere Block (hier `sidebar` und `main`) ist dabei unabhängig überschreibbar. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{# Basis-Template #}} {{ block "content" }} {{ block "sidebar" }} {{ /block }} {{ block "main" }}
Standard-Inhalt
{{ /block }} {{ /block }} ``` ### Negativbeispiel Ein View-Template, das `{{ extends }}` verwendet, darf ausschließlich aus Blockanweisungen bestehen. Code oder HTML außerhalb eines Blocks ist ungültig und führt zu Fehlern. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{# Ungültig – Code außerhalb eines Blocks #}} {{ extends "layouts/default.htm" }}

Dieser Text steht außerhalb eines Blocks – das funktioniert nicht.

{{ block "content_main" }}

Das hier ist korrekt.

{{ /block }} ``` # Components Source: https://dokumentation.websale.de/frontend/referenz/components Components der WEBSALE Template-Sprache: wiederverwendbare Bausteine für strukturierte, modulare Frontend-Komponenten im Shop-Template. # Conditions Source: https://dokumentation.websale.de/frontend/referenz/conditions Conditions in der WEBSALE Template-Sprache: Bedingungen formulieren und Ausgaben oder Template-Logik abhängig von Werten und Status steuern. # Datentypen Source: https://dokumentation.websale.de/frontend/referenz/datentypen Basisdatentypen der WEBSALE Template-Sprache: String, Zahl, Bool, Listen und Maps korrekt notieren und im Template sicher verarbeiten. Man unterscheidet folgende Basisdatentypen: ## String Ein String ist eine Zeichenkette, d. h. eine Folge von Zeichen (z. B. Buchstaben, Ziffern, Sonderzeichen und Steuerzeichen). Strings müssen immer zwischen zwei Hochkommas oder Anführungszeichen notiert werden. | | | | ------------------------------ | -------------------------------------- | | `"Wert1, Wert2, Wert3, Wert4"` | String | | `'Wert1, Wert2, Wert3, Wert4'` | String | | `Wert1, Wert2, Wert3, Wert4` | kein String (Anführungszeichen fehlen) | ## Konkatenation Mit dem `+`-Operator ist es möglich mehrere Strings zusammenzustellen. In diesem Beispiel erstellen wir Variablen für eine Begrüßung und stellen wir zusammen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $greeting = "Willkommen " }} {{ var $customer = "Neukunde"}} {{ var $genericGreeting= $greeting + $customer}} {{= $genericGreeting}} // Wilkommen Neukunde ``` Nur Strings können konkateniert werden. Dennoch ist es möglich andere Variablen in ein String zu konvertieren um sie mit einem String zu konkatenieren. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $menge = 1}} {{ var $text = "Anzahl: " + string($menge) + "!" }} {{= $text}} // Anzahl: 1! ``` Es können andere Basistypen in String konvertiert werden: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Boolean: {{= string(true) }} // "true" Integer: {{= string(1) }} // "1" Float: {{= string(1.1) }} // "1.1" ``` ## Integer Integer sind Ganzzahlen (Zahlen ohne Nachkommastellen). | | | | ------- | ----------------------------------------- | | `10` | Integer | | `20.00` | kein Integer (Nachkommastellen vorhanden) | ## Float Floats sind Fließkommazahlen mit einem **Punkt** als Dezimaltrenner. | | | | ------- | ------------------------------------------------------- | | `10.25` | Float | | `10,25` | kein Float (ungültige Syntax: Komma als Dezimaltrenner) | ### Float konvertieren Es können andere Basistypen in Float konvertiert werden ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} String: {{= float("1.1")}} // 1.1 Integer: {{= float(1) }} // 1.0 Boolean: {{= float(true) }} // 1.0 ``` ## Boolean/Bool (true/false) Ein Bool ist ein Wahrheitswert und kann nur *true* (wahr) oder *false* (falsch) sein. | | | | -------- | ------------------------------------------- | | `true` | Wahrheitswert true | | `false` | Wahrheitswert false | | `"true"` | kein Wahrheitswert (falsche Syntax: String) | Boolesche Werte werden meistens in Kombination mit [Vergleichsoperatoren](/frontend/referenz/operatoren) erzeugt. Wenn man beispielsweise einen Wert mit einem anderen vergleicht, ist das Ergebnis entweder wahr oder falsch. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $quantity == 1 }}     Wird angezeigt, wenn der Wert der Variable $quantity gleich 1 ist. {{ /if }} ``` ### truthy und falsy Nicht nur Werte vom Datentyp Bool enthalten einen Wahrheitswert. Objekte aller anderen Datentypen haben ebenfalls eine Werte-Eigenschaft, die man als *truthy* oder *falsy* bezeichnet. In Zusammenhang mit logischen Operatoren und Verzweigungen ist es wichtig zu wissen, wann ein Wert als wahr oder falsch angesehen wird. Hier eine Auflistung aller Werte die *falsy* sind und deshalb als *false* behandelt werden: ▪\_null\_, der Wert des Datentyps Null ▪\_false\_ ▪die Zahl 0 (*Integer*) oder 0.0 (*Float*) ▪ein leerer *String " "* ▪eine leere *List \[ ]* ▪eine leere *Map* Alle anderen Werte werden als *truthy* behandelt. ### Boolean konvertieren Es können andere Basistypen in Boolean konvertiert werden ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} String: {{= bool(" ")}} // true String: {{= bool("")}} // false Integer: {{= bool(1) }} // true Integer: {{= bool(0) }} // false Float: {{= bool(1.0) }} // true Float: {{= bool(0.0) }} // false ``` ## List Eine List ist eine Reihe von Werten, die kommasepariert zwischen eckigen Klammern stehen. Eine leere List wird mit eckigen Klammern ohne Inhalt geschrieben. | | | | ----------- | ------------- | | `[1, 2, 3]` | gefüllte List | | `[ ]` | leere List | Die Leerzeichen zwischen den Werten sind optional. ## Distinct Wenn in einer Liste mehrere Einträge gibt, die identisch sind, kann mit dieser Funktion alle doppelten Einträge entfernt werden. **Argumente** `list` - Liste, die verarbeitet werden soll `key` - (Optional) Map-Key, der für den Vergleich mit anderen Maps hergenommen werden soll. **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $list = [ 1, 2, 3, 4, 3, 2, 5, 6, 1 ] }} {{= distinct($list) }} // Ergebnis: [ 1, 2, 3, 4, 5, 6 ] {{ $list = [ "a", 1, "b", true, 2, "a", true, true, {"x": 1, "y": 1}, {"x": 1, "y": 2} ] }} {{= distinct($list) }} // Ergebnis: [ "a", 1, "b", true, 2, , {"x": 1, "y": 1}, {"x": 1, "y": 2} ] ``` Man kann bei für Objekte einen key angeben, mit dem definiert werden soll welches Feld zum Vergleich hergenommen werden soll. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $list = [ 1, {"x": 1, "y": 1}, {"x": 1, "y": 2}, {"x": 2, "y": 2} ] }} {{= $list | distinct("x") }} // Ergebnis: [ 1, {"x": 1, "y": 1}, {"x": 2, "y": 2} ] ähnliche Schreibweise ohne Pipe: {{= distinct($list, "x") }} ``` ## Merge Es können zwei Listen jeweils miteinander vereint werden. Zusätzliche Information: Neben der Verwendung von einer Funktion kann auch der `+`-Operator (`$list1 + $list2`) verwendet werden. **Argumente** `target` - Liste, die für das Zusammenführen als Basis hergenommen werden soll `source` - Liste, um die das `target` erweitert werden soll ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $list1 = [ 1, 2, 3 ] }} {{ var $list2 = [ 3, 4, 5] }} {{ var $list3 = merge($list1, $list2) }} {{= $list3 }} // Ergebnis: [1, 2, 3, 3, 4, 5] ``` ## Map Eine Map ist eine Liste von Schlüssel-Wert-Paaren, die innerhalb einfacher geschweifter Klammern geschrieben werden. Der Schlüssel und sein Wert werden durch Doppelpunkt getrennt. Die einzelnen Schlüssel-Wert-Paare werden durch Kommas getrennt. Eine leere Map wird mit geschweiften Klammern ohne Inhalt geschrieben. | | | | ------------------------------------------------------------ | ---------------------------- | | `{ name: "Shirt", price: "12.95", image: "shirt-blue.jpg" }` | gefüllte Map | | `{ "404": "Not found", "301": "Moved Permanently" }` | gefüllte Map | | `{ "Name, Description , Price, Zusatzinfos" }` | keine Map (ungültige Syntax) | | `{ }` | leere Map | Wenn ein Schlüssel andere Zeichen enthält als Ziffern (0-9), Buchstaben (a-z, A-Z) oder Unterstriche (\_) oder mit einer Ziffer/Unterstrich beginnt, muss dieser als String in Anführungszeichen angegeben werden. Bei der Ausgabe von Maps wird die Reihenfolge der einzelnen Schlüssel-Werte-Paare nicht berücksichtigt. ### **Merge** Es können zwei Maps jeweils miteinander vereint werden. Bei der Map wird bei unterschiedlichen Inhalten der Inhalt des zweite Eintrags verwendet. Dabei kann auch verschachtelte Maps berücksichtigt werden. **Argumente** `target` - Map, die für das Zusammenführen als Basis hergenommen werden soll `source` - Map, um die das `target` erweitert werden soll `deep` - Optionaler Flag ob ein die Verschachtelung von Maps berücksichtigt werden soll (default: `false`) Beispiel - Merge von zwei Maps. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $map1 = { "a": 1, "b": 2, "c": { "x": 10, "y": 11 } } }} {{ var $map2 = { "a": 2, "c": { "z": 12 }, "d": true } }} {{ var $map3 = merge($map1, $map2) }} {{= $map3 }} // Ergebnis: { "a": 2, "b": 2, "c":{ "z": 12 }, "d": true } ``` Beispiel - Deep Merge von zwei Maps: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $map1 = { "a": 1, "b": 2, "c": { "x": 10, "y": 11 } } }} {{ var $map2 = { "a": 2, "c": { "z": 12 }, "d": true } }} {{ var $map3 = merge($map1, $map2, true) }} {{= $map3 }} // Ergebnis: { "a": 2, "b": 2, "c":{ "x": 10, "y": 11, "z": 12 }, "d": true } ``` # Funktionen Source: https://dokumentation.websale.de/frontend/referenz/funktionen Globale Template-Funktionen: Strings anpassen, Zahlen runden, Listen zusammenführen und Datumswerte vergleichen – inklusive Modifier-Nutzung. Globale Template-Funktionen stehen in allen Templates zur Verfügung. Sie werden verwendet, um Werte zu verarbeiten, zu formatieren oder zu prüfen (z. B. Strings anpassen, Zahlen runden, Listen zusammenführen oder Datumswerte vergleichen). Diese Seite beschreibt ausschließlich globale Funktionen. Funktionen, die an ein Modul gebunden sind (z. B. Methoden von `$wsAccount` oder `$wsExternalData`), werden in der jeweiligen [Modul-Referenz](../referenz/module.mdx) dokumentiert. Viele Funktionen können alternativ auch als [Modifier](../referenz/modifiers.mdx) (Filter) verwendet werden. *** ## Grundlagen Funktionen werden mit runden Klammern aufgerufen. Werte, die an eine Funktion übergeben werden (sogenannte Parameter), werden durch Kommas getrennt. Funktionsnamen sind case-sensitive (Groß - und Kleinschreibung muss also genau beachtet werden). ### Schreibweise Damit das Ergebnis einer Funktion im Template ausgegeben wird, wird die Ausgabe-Schreibweise verwendet: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= (...) }} ``` Das Ergebnis der Funktion muss nicht zwingend sofort im Template ausgegeben werden, sondern kann auch in einer eigenen Variable gespeichert werden, um es später weiter zu verwenden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myVariable = (...) }} ``` ### Parameterübergabe und Reihenfolge Standardmäßig werden Parameter positionsbasiert übergeben (in der Reihenfolge der Signatur). Wenn die Reihenfolge der Parameter geändert werden soll, müssen benannte Parameter verwendet werden (Name laut Signatur + `=`). Entscheidend sind dann die Parameternamen – nicht die Position. **Beispiel** Ein Gutschein soll über die Funktion `replace` umbenannt werden. Aus `GUTSCHEIN_buy10` soll `GUTSCHEIN_sale10` werden. Die Signatur lautet: `replace(content, search, replace)`. Bei positionsbasierter Übergabe ist die Reihenfolge daher: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= replace("GUTSCHEIN_buy10", buy", "sale") }} ``` Sobald Parameter benannt übergeben werden (`name="..."`), ist die Reihenfolge frei: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= replace(search="buy", replace="sale", content="GUTSCHEIN_buy10") }} ``` \= In beiden Fällen ist das Ergebnis ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GUTSCHEIN_sale10 ``` ### Funktionen kombinieren (verkettete Verarbeitung) Mehrere Funktionen können auch nacheinander angewendet werden, indem die erste Funktion als Argument der zweiten Funktion verwendet wird. **Beispiel** Die VersandkostenID „versand\_kostenfrei“ soll sprechend in „VERSAND KOSTENFREI“ umbenannt und die Schreibweise in Versalien (Großschreibung) geändert werden. Es werden die Funtkionen `upper` und `replace` verwendet: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= upper(replace("versand_kostenfrei", "_", " ")) }} ``` \= ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} VERSAND KOSTENFREI ``` ### Texte und Listen zusammenfügen Mit dem `+`-Operator könne zwei Texte (Strings) direkt zu einem neuen String zusammengefügt werden. Für Listen kann `+` alternativ zu `merge()` verwendet werden, um zwei Auflistungen zu vereinen. Es können nur Werte desselben Typs mit `+` verbunden werden. Zahlen oder andere Typen müssen vorher mit der Funktion `str()` in einen Text umgewandelt werden. **Beispiele**\ Artikelnummer aus Präfix und ID zusammensetzen: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $prefix = "ART-" }} {{ var $productId = "10452" }} {{ var $articleNumber = $prefix + $productId }} {{= $articleNumber }} ``` **Ausgabe** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ART-10452 ``` Bestellmenge in einen Hinweistext einbinden - Zahlen müssen vor der Zusammensetzung mit einem String mit `str()` in einen Text umgewandelt werden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $quantity = $wsCart.info.itemCount }} {{ var $message = "Anzahl Artikel im Warenkorb: " + str($quantity) }} {{= $message }} ``` *** ## Liste der Funktionen ### abs Die Funktion `abs` gibt den Absolutwert einer Zahl zurück – also den Wert ohne Vorzeichen. Eine negative Zahl wird dadurch positiv, eine positive Zahl bleibt unverändert. **Anwendungsbeispiel**\ Nützlich, um z. B. Rabattbeträge oder Preisdifferenzen im Shop immer als positive Zahl darzustellen – unabhängig davon, ob der Wert in den Daten ein Minus-Vorzeichen hat. **Signatur**\ `abs(value)` **Parameter** * `value` - Die Zahl, deren Absolutwert ermittelt werden soll. **Verwendbar als Modifier**\ ja **Beispiel mit negativem Wert** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= abs(-7.5) }} ``` **Ausgabe** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 7.5 ``` **Beispiel mit positivem Wert** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= abs(3) }} ``` **Ausgabe** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 3 ``` **Beispiel - Preisdifferenz immer positiv darstellen**\ Der aktuelle Preis eines Produkts wird im Feld `price` gespeichert (hier: `79.95`), der ursprüngliche Preis im Feld `setOrgPrice` (hier: `99.95`). Die Differenz zwischen beiden kann je nach Rechenrichtung negativ ausfallen. Mit `abs` wird sichergestellt, dass der angezeigte Betrag immer positiv ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProduct = $wsProducts.load("100-12345") }}

Sie sparen: {{= currency(abs($myProduct.price - $myProduct.setOrgPrice)) }} €

``` **Ausgabe** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Sie sparen: 20,00 € ``` *** ### ceil Die Funktion `ceil` rundet eine Zahl immer auf die nächste ganze Zahl auf – egal, wie klein der Nachkommaanteil ist. `ceil(1.1)` ergibt also `2`, genauso wie `ceil(1.9)`. **Anwendungsbeispiel**\ Hilfreich, wenn Werte im Shop immer „zugunsten" einer ganzen Einheit aufgerundet werden sollen – z. B. Stückzahlen, Verpackungseinheiten oder berechnete Mengen. **Signatur**\ `ceil(value)` **Parameter** * `value` – Die Zahl, die aufgerundet werden soll. **Verwendbar als Modifier:**\ ja **Beispiel mit Dezimalzahl resp. Dezimalbruch** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= ceil(1.3) }} ``` **Ausgabe** (aufgerundet auf die nächste ganze Zahl) ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 2.000000 ``` **Beispiel mit ganzer Zahl (Ganzzahl)** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= ceil(2) }} ``` **Ausgabe** (ganze Zahl bleibt unverändert) ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 2.000000 ``` Um die Darstellung der Nachkommastellen anzupassen benutzen Sie `ceil(2) | preparedFormat(“name“)` \ **Beispiel - Berechnetes Produktgewicht aufrunden**\ Das Versandgewicht eines Produkts (in diesem Fall 2,3 kg) wird auf volle Kilogramm aufgerundet. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProductWeight = $myProduct.custom.weight }}

Versandgewicht: {{= ceil($myProductWeight) | preparedFormat("amount") }} kg

``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Versandgewicht: 3 kg ``` **Gegenstück**\ [floor](#floor) *** ### currency Die Funktion `currency` formatiert einen numerischen Wert als Preisangabe gemäß den [Shop-Einstellungen zur Währung](/konfiguration/finance-wahrungen-steuern). Dazu gehören insbesondere: * Dezimaltrennzeichen (z. B. `,` statt `.`) * Anzahl der Nachkommastellen (z. B. 2 bei vielen Währungen) * kaufmännisches Runden auf die konfigurierte Nachkommastellen-Anzahl Die Funktion berechnet keine Preise (z.B. Steuern, Rabatte oder Versandkosten), sondern formatiert ausschließlich den übergebenen Wert für die Ausgabe. **Anwendungsbeispiel**\ Eignet sich für die Ausgabe von Beträgen wie Einzelpreisen, Rabatten, Zwischensummen und Gesamtsummen. **Signatur**\ `currency(price)` **Parameter** * `price` - Die Zahl, die als Preis formatiert werden soll. **Verwendbar als Modifier**\ ja **Beispiel mit Nachkommastellen** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= currency(3.1475) }} ``` **Ausgabe** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 3,15€ ``` **Beispiel mit Ganzzahl** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= currency(12) }} ``` **Ausgabe** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 12,00€ ``` Soll ein Zahlenwert unabhängig von der Währung in einem bestimmten Format ausgegeben werden (z.B. mit einer anderen Anzahl an Nachkommastellen), ist [preparedFormat()](#preparedformat) die passende Funktion. **Beispiel - Produktpreis formatiert ausgeben**\ Der Preis eines Produkts wird als Dezimalzahl gespeichert (hier: `89.95`). Mit `currency` wird er gemäß den Shop-Einstellungen formatiert. **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 89.95€ ``` *** ### dateFmt Die Funktion `dateFmt` bringt ein Datum oder einen Zeitpunkt in ein gewünschtes Anzeigeformat. Der Eingabewert muss im ISO-8601-Format vorliegen (z. B. `2018-03-11T11:20:11.000Z`) – dieses Format wird von den meisten Systemen automatisch verwendet. **Anwendungsbeispiel**\ Damit lassen sich z. B. Bestelldaten, Liefertermine oder Aktionszeiträume im Shop leserlich darstellen (z. B. als „11.03.2018" oder „11:20:11"). **Signatur**\ `dateFmt(isoDate, fmt[, tz])` **Parameter** * `isoDate` – Datum/Zeit im ISO-8601-Format (z. B. `2018-03-11T11:20:11.000Z`) * `fmt` – Formatangabe, die festlegt, wie die Ausgabe aussehen soll * Die wichtigsten Platzhalter im Überblick * `%d` = Tag (01–31) * `%m` = Monat (01–12) * `%Y` = Jahr (4-stellig) * `%H` = Stunde (00–23) * `%M` = Minute (00–59) * `%S` = Sekunde (00–60) * Damit können Sie die folgenden Formate einfach „zusammenbauen“, z. B.: * `"%d.%m.%Y"` → `11.03.2018` * `"%H:%M:%S"` → `11:20:11` * `tz` (optional) – Zeitzone, in der die Zeit ausgegeben werden soll (z.B. "`Europe/Berlin`"). Ohne Angabe wird die im Shop konfigurierte Zeitzone verwendet (Konfiguration [general.general](https://dokumentation.websale.de/konfiguration/general-allgemeine-shopeinstellungen#general-general-allgemeine-basiseinstellungen), auch über [\$wsSubshop.timeZone](/frontend/referenz/module/wssubshop#wssubshop-timezone) abrufbar). Gültige Werte sind die Namen der IANA-Zeitzonendatenbank, [eine gut lesbare Übersicht finden Sie hier](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). **Verwendbar als Modifier**\ ja **Beispiel zur Ausgabe des Bestelldatums aus der “Bestellzeit”** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= dateFmt("2018-03-11T11:20:11.000Z", "%d.%m.%Y") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 11.03.2018 ``` **Beispiel zur Ausgabe der Uhrzeit aus der “Bestellzeit”** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= dateFmt("2018-03-11T11:20:11.000Z", "%H:%M:%OS") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 11:20:11 ``` **Beispiel mit Ausgabe der Zeitzone**\ Derselbe UTC-Zeitstempel wird in der Zeitzone `Europe/Berlin` ausgegeben. Im März gilt dort die Mitteleuropäische Zeit (UTC+1), die Uhrzeit liegt daher eine Stunde später als in der UTC-Eingabe. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= dateFmt("2018-03-11T11:20:11.000Z", "%H:%M", "Europe/Berlin") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 12:20 ``` **Beispiel - aktuelle Jahreszahl ausgeben**\ In Kombination mit [\$wsSubshop.currentTime](/frontend/referenz/module/wssubshop) (aktueller Zeitstemple im ISO-8601-Format) lässt sich z.B. die aktuelle Jahreszahl ausgeben. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsSubshop.currentTime | dateFmt("%Y") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 2026 ``` **Beispiel - Bestelldatum und Uhrzeit formatiert ausgeben**\ Das Bestelldatum ist in diesem Beispiel in folgendem Format gespeichert - `2024-06-15T14:32:05.000Z`. Mit `dateFmt` wird es für eine Bestellbestätigung in ein lesbares Datum und eine separate Uhrzeit umgewandelt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{var $myOrder = $wsOrderHistory.load($wsViews.current.params.orderHistorySelect)}

Bestellt am: {{= dateFmt($myOrder.general.dateTime, "%d.%m.%Y") }}

Uhrzeit: {{= dateFmt($myOrder.general.dateTime, "%H:%M") }} Uhr

``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Bestellt am: 15.06.2024 Uhrzeit: 14:32 Uhr ``` *** ### dateGreaterThan Die Funktion `dateGreaterThan` vergleicht zwei Datumswerte (als Strings) miteinander und liefert `true`, wenn das erste Datum nach dem zweiten Datum liegt. **Anwendungsbeispiel**\ Damit lässt sich im Template z. B. prüfen, ob ein Liefertermin in der Zukunft liegt oder ob ein Zeitraum bereits überschritten ist. **Signatur**\ `dateGreaterThan(firstDate, secondDate)` **Parameter:** * `firstDate` – Erstes Datum (zu prüfender Wert) * `secondDate` – Zweites Datum (Vergleichswert) **Verwendbar als Modifier**\ ja **Beispiel eines Datumsvergleichs** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= dateGreaterThan("2019-03-11T11:20:11.000Z", "2017-07-11T11:20:11.000Z") }} ``` **Ausgabe** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} true ``` **Beispiel - Prüfen, ob eine Bestellung nach einem bestimmten Stichtag aufgegeben wurde**\ Mit `dateGreaterThan` lässt sich prüfen, ob die Bestellung nach einem festen Stichtag liegt - z.B. um nur Bestellungen ab dem 01.01.2025 für eine Rückgabeaktion zu berücksichtigen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myOrder = $wsOrderHistory.load("12345") }} {{ var $stichtag = "2025-01-01T00:00:00.000Z" }} {{ if (dateGreaterThan($myOrder.general.dateTime, $stichtag)) }}

Diese Bestellung ist für die Rückgabeaktion qualifiziert.

{{ /if }} ``` **Ausgabe, wenn das Bestelldatum nach dem 01.01.2025 liegt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Diese Bestellung ist für die Rückgabeaktion qualifiziert. ``` **Gegenstück**\ [dateLessThan](#datelessthan) *** ### dateLessThan Die Funktion `dateLessThan` vergleicht zwei Datumswerte (als Strings) miteinander und liefert `true`, wenn das erste Datum **vor** dem zweiten Datum liegt. **Anwendungsbeispiel**\ Damit lassen sich im Template z. B. Fristen oder Zeiträume prüfen - etwa ob ein Datum bereits überschritten ist oder ob ein Ereignis noch bevorsteht. **Signatur**\ `dateLessThan(firstDate, secondDate)` **Parameter** * `firstDate` – Erstes Datum (zu prüfender Wert) * `secondDate` – Zweites Datum (Vergleichswert) **Verwendbar als Modifier**\ ja **Beispiel eines Datumsvergleichs** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= dateLessThan("2020-03-11T11:20:11.000Z", "2021-07-11T11:20:11.000Z") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} true ``` **Beispiel - Hinweis anzeigen, wenn eine Bestellung vor einem Stichtag aufgegeben wurde**\ Mit `dateLessThan` lässt sich prüfen, ob die Bestellung vor einem festen Stichtag liegt - z.B. um drauf hinzuweisen, dass die Rückgabefrist bereits abgelaufen ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myOrder = $wsOrderHistory.load("12345") }} {{ var $fristEnde = "2025-01-01T00:00:00.000Z" }} {{ if (dateLessThan($myOrder.general.dateTime, $fristEnde)) }}

Die Rückgabefrist für diese Bestellung ist abgelaufen.

{{ /if }} ``` **Ausgabe, wenn das Bestelldatum vor dem 01.01.2025 liegt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Die Rückgabefrist für diese Bestellung ist abgelaufen. ``` **Gegenstück**\ [dateGreaterThan](#dategreaterthan) *** ### decode Die Funktion `decode` wandelt einen kodierten String zurück in seinen ursprünglichen Klartext. Unterstützte Formate sind `base64` und `hex`. Wenn der übergebene Wert kein gültiger kodierter String im angegebenen Format ist, gibt die Funktion `null` zurück. **Anwendungsbeispiel**\ Nutzbar, um z.B. extern kodiert übermittelte Produktdaten, Gutscheincodes oder Konfigurationswerte vor der Weiterverarbeitung im Template zu dekodieren. **Signatur**\ `decode(content, format)` **Parameter** * `content` - Der kodierte String, der dekodiert werden soll. * `format` - Das Kodierungsformat, das beim Dekodieren verwendet werden soll. Gültige Werte: `“base64”`, `“hex”`. **Verwendbar als Modifier**\ ja **Beispiel - Dekodierung eines Base64-Strings** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= decode("d2Vic2FsZQ==", "base64") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} websale ``` **Beispiel - Dekodierung eines Hex-Strings** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= decode("776562 73616c65", "hex") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} websale ``` **Beispiel - Fehlerhafte Eingabe** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= decode("kein-gültiger-base64-wert!!!", "base64") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} null ``` **Gegenstück**\ [encode](#encode) *** ### distinct Die Funktion `distinct` entfernt doppelte Einträge aus einer Auflistung und gibt eine neue Auflistung zurück, in der jeder Wert nur einmal vorkommt. Bei Auflistungen von Datenobjekten (Maps) kann optional ein Schlüssel angegeben werden, anhand dessen verglichen wird. Die Angabe des Schlüssels wird nur auf der obersten Ebene einer Map berücksichtigt. **Anwendungsbeispiel**\ Nutzbar, um z.B. Duplikate aus einer Liste von Produktkategorien, Variantenmerkmalen oder Filterwerten zu entfernen, bevor sie im Template angezeigt werden. **Signatur**\ `distinct(list[, key]` **Parameter** * `list` - Die Auflistung, aus der Duplikate entfernt werden sollen. * `key (optional)` - Schlüssel eines Datenobjekts, der für den Vergleich verwendet wird. **Verwendbar als Modifier**\ ja **Beispiel - Doppelte Größenangaben aus einer Variantenliste entfernen** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $sizes = ["S", "M", "L", "M", "XL", "S"] }} {{= distinct($sizes) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ["S", "M", "L", "XL"] ``` *** ### encode Die Funktion `encode` kodiert einen String ein ein angegebenes Format. Unterstützte Formate sind `base64` und `hex`. Der Rückgabewert ist immer vom Typ String. **Anwendungsbeispiel**\ Nutzbar, um z.B. Gutscheincodes, Produkt-Kennungen oder andere Werte für die Weitergabe an externe Dienste oder in URLs sicher zu kodieren. **Signatur**\ `encode(content, format)` **Parameter** * `content` - Der String, der kodiert werden soll. * `format` - Das Zielformat der Kodierung. Gültige Werte: `“base64”`, `“hex”`. **Verwendbar als Modifier**\ ja **Beispiel - Kodierung als Base64** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= encode("websale", "base64") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} d2Vic2FsZQ== ``` **Beispiel - Kodierung als hex** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= encode("websale", "hex") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 776562 73616c65 ``` **Gegenstück**\ [decode](#decode) *** ### floor Die Funktion `floor` rundet eine Zahl immer auf die nächste ganze Zahl ab – egal, wie groß der Nachkommaanteil ist. `floor(4.9)` ergibt also `4`, genauso wie `floor(4.1)`. **Anwendungsbeispiel**\ Hilfreich, wenn Werte im Shop grundsätzlich abgerundet werden sollen – z. B. bei berechneten Mengen oder Zwischenergebnissen, die nur als ganze Zahl weiterverarbeitet werden dürfen. **Signatur**\ `floor(value)` **Parameter** * `value` – Numerischer Wert, der abgerundet werden soll. **Verwendbar als Modifier**\ ja **Beispiel mit Dezimalzahl resp. Dezimalbruch** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= floor(4.9) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 4.000000 ``` **Beispiel mit ganzer Zahl** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= floor(2) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 2.000000 ``` Um die Darstellung der Nachkommastellen anzupassen benutzen Sie `floor(4.9) | preparedFormat(“name”)` **Beispiel - Berechnetes Produktgewicht abrunden**\ Das Versandgewicht eines Produkts (in diesem Fall 2,7 kg) wird auf volle Kilogramm abgerundet. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProductWeight = $myProduct.custom.weight }}

Mindestgewicht: {{= floor($myProductWeight) | preparedFormat("amount") }} kg

``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Mindestgewicht: 2 kg ``` **Gegenstück**\ [ceil](#ceil) *** ### ifnull Die Funktion `ifnull` prüft, ob ein Wert vorhanden ist oder nicht (`null` bedeutet: „kein Wert vorhanden"). Ist der Wert `null`, wird stattdessen ein Ersatzwert ausgegeben. Ist ein Wert vorhanden, wird dieser selbst verwendet. **Anwendungsbeispiel**\ Eignet sich z.B. für Fallback-Logiken im Shop - etwa um ein Ersatzbild anzuzeigen, wenn kein Produktbild vorhanden ist, oder um fehlende Produktdaten durch Standardwerte zu ersetzen. **Signatur**\ `ifnull(object, value)` **Parameter** * `object` - Der zu prüfende Wert. * `value` - Der Alternativwert, der ausgegeben wird, wenn `object` den Wert `null` hat. **Verwendbar als Modifier**\ ja **Beispiel mit** `null`**-Wert** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= ifnull(Null, "sale") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} sale ``` **Beispiel mit vorhandenem Wert** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= ifnull("web", "sale") }} ``` **Ausgabe** (der String `“web”` ist nicht `null`, daher wird er selbst ausgegeben). ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} web ``` **Beispiel mit Produktbild-Fallback**\ In der Variable `$myProduct` werden alle Informationen und Daten zu einem Produkt gespeichert. Wenn kein Produktbild gefunden wird (`$myProduct.custom.image.normal` ist `null`), dann wird das Ersatzbild `noImageNormal.png` angezeigt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProduct = $wsView.info.product }} ``` *** ### int Die Funktion `int` wandelt einen Wert in eine ganze Zahl (Integer) um. Das ist vor allem dann nötig, wenn ein Zahlenwert als Text vorliegt (z.B. `“10”`) und als echte Zahl weiterverarbeitet werden soll - etwa für Berechnungen oder Vergleiche. Ist die Umwandlung nicht möglich (z.B. bei einem Wort), wird `null` zurückgegeben. Dezimalzahlen werden auf die ganze Zahl vor dem Komma gekürzt (nicht gerundet). **Anwendungsbeispiel**\ Nutzbar, um z. B. Mengenangaben oder Artikel-IDs, die als Text vorliegen (z.B. “1043”), in eine Zahl umzuwandeln, bevor sie weiterverarbeitet werden. **Signatur**\ `int(value)` **Parameter** * `value` - Der Wert, der in eine Ganzzahl konvertiert werden soll. **Verwendbar als Modifier**\ ja **Beispiel mit einem String, der eine Zahl enthält** Der Text “10” wird in die Zahl 10 umgewandelt. Mit der Ausgabe wurde der Text in eine Zahl konvertiert, mit der nun gerechnet werden kann. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= int("10") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 10 ``` **Beispiel mit nicht konvertierbarem Wert** Ein Wort (in diesem Fall “websale”) kann nicht ein eine Zahl umgewandelt werden - die Ausgabe ist `null`. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= int("websale") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} null ``` **Beispiel mit Dezimalzahl** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= int(10.789) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 10 ``` *** ### isoToUnix Die Funktion `isoToUnix` wandelt einen Zeitstempel im ISO-8601-Format in die Unix-Zeit um, also die Anzahl der Sekunden seit dem 1.Jahnuar 1970 (UTC).\ \ **Anwendungsbeispiel**\ Nutzbar, um z.B. Zeitstempel für Berechnungen, Vergleiche oder die Übergabe an externe Dienste in ein einheitliches numerisches Format zu bringen.\ \ **Signatur**\ `isoToUnix(isoDate)` **Parameter** * `isoDate` - Zeitstempel im ISO-8601-FOrmat (z.B. 2018-03-11T11:20:11.000Z) **Verwendbar als Modifier**\ ja **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= isoToUnix("2018-03-11T11:20:11.000Z") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 1520767211 ``` **Gegenstück**\ [unixToIso](https://dokumentation.websale.de/frontend/referenz/funktionen#unixtoiso) *** ### join Die Funktion `join` fügt alle Einträge einer Auflistung zu einem String zusammen. Optional kann ein Separator (Trennzeichen) angegeben werden, der die Elemente voneinander trennt. **Anwendungsbeispiel**\ Eignet sich z. B. um Produkteigenschaften, Variantenmerkmale oder Kategorien als zusammenhängenden Text auszugeben – etwa kommasepariert in einer Zeile. **Signatur**\ `join(list[, "separator"])` **Parameter** * `list` - Die Auflistung, deren Einträge zusammengefügt werden sollen. * `separator` (optional) - Trennzeichen zwischen den Einträgen. Standard: kein Trennzeichen. **Verwendbar als Modifier**\ ja **Beispiel ohne Separator** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= join(["S", "M", "L", "XL"]) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} SMLXL ``` **Beispiel mit Separator** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= join(["S", "M", "L", "XL"], ", ") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} S, M, L, XL ``` **Beispiel - verfügbare Farben eines Produkts als Text ausgeben**\ Die Varianten-Daten eines Produkts werden über `$wsProducts.variantInfo()` geladen. Das Attribut “Farbe” enthält eine Auflistung von Optionen (hier: `“Rot”`, `“Blau”`, `“Grün”`). Die Farbnamen werden in einer Schleife gesammelt, mit [push](#push) in einer Auflistung gesammelt und mit `join` zu einem lesbaren Text zusammengefügt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myVariants = $wsProducts.variantInfo("100-12345") }} {{ var $colors = [] }} {{ for $myOption in $myVariants.variantAttributes[0].options }} {{ push($colors, $option.name) }} {{ /for }}

Verfügbare Farben: {{= join($colors, ", ") }}

``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Verfügbare Farben: Rot, Blau, Grün ``` **Gegenstück**\ [split](#split) *** ### json Die Funktion `json` gibt ein Datenobjekt in der technischen JSON-Schreibweise aus – einem standardisierten Textformat, das sich leicht maschinell verarbeiten lässt. **Anwendungsbeispiel**\ Nützlich zum Fehlersuchen (Debugging) im Template oder bei der Weitergabe von Daten an externe Dienste (z. B. Tracking, Analytics). **Signatur**\ `json(object)` **Parameter** * `object` - Das Objekt, das als JSON-String ausgegeben werden soll. **Verwendbar als Modifier**\ ja **Beispiel - Ausgabe von Produktdaten zur Fehlersuche** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $product = $wsView.info.product }}
{{= json($product) }}
``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {"name":"Sneaker Classic","price":89.95,"sku":"SNK-001","sizes":["40","41","42"]} ``` Es werden nicht mehr als fünf Ebenen ausgegeben. Tiefere Ebenen werden als `“…”` dargestellt. *** ### keys Die Funktion `keys` gibt alle Bezeichner (Schlüssel) eines Datenobjekts (Map) als Auflistung zurück. Eine Map besteht aus Paaren von Bezeichnern und Werten – z. B. `{name: "Topseller", price: 12.99}`. Mit `keys` lassen sich gezielt die Bezeichner auslesen. **Anwendungsbeispiel**\ Nutzbar, um z. B. über alle Einträge eines Datenobjekts zu gehen und sowohl die Bezeichner als auch die zugehörigen Werte im Template anzuzeigen – etwa bei dynamisch aufgebauten Produktdaten oder Konfigurationseinstellungen. **Signatur**\ `keys(object)` **Parameter** * `object` - Das Datenobjekt, dessen Bezeichner (Schlüssel) zurückgegeben werden sollen. **Verwendbar als Modifier**\ ja **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= keys({name: "Topseller", price: 12.99, description: "Beschreibung"}) }} ``` **Ausgabe** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ["description","price","name"] ``` *** ### last Die Funktion `last` gibt den letzten Eintrag einer Auflistung (List) zurück. **Anwendungsbeispiel**\ Nutzbar, um z.B. die letzte Bestellposition, den letzten Breadcrumb-Eintrag oder das letzte Element einer Variantenliste gezielt anzuzeigen. **Signatur**\ `last(list)` **Parameter** * `list` - die Auflistung, deren letzter Eintrag zurückgegeben werden soll. **Verwendbar als Modifier**\ ja **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= last(["a", "b", "c", "d"]) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} d ``` **Beispiel - Letzten Breadcrumb-Eintrag als aktuelle Kategorie anzeigen**\ Der Kategoriepfad (Breadcrumb) wird über `$wsCategories.loadPath()` als Auflistung geladen. Mit `last` wird der letzte Eintrag gezielt ausgelesen, da dieser der aktuellen Kategorie entspricht. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myBreadcrumb = $wsCategories.loadPath($category.id) }}

Kategorie: {{= last($myBreadcrumb).name }}

``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Sneaker ``` *** ### len Die Funktion `len` ermittelt die Länge, also die Anzahl der Zeichen bei einem Text, die Anzahl der Einträge bei einer Auflistung oder die Anzahl der Schlüssel-Wert-Paare bei einem Datenobjekt. **Anwendungsbeispiel**\ Nutzbar, um z.B. die Anzahl von Produkten in einer Liste zu zählen, die Zeichenlänge einer Eingabe zu prüfen oder um festzustellen, wie viele Einträge ein Datenobjekt enthält. **Signatur**\ **len(sequence)** **Parameter** * `sequence` - Text, Auflistung oder Datenobjekt, dessen Länge ermittelt werden soll. **Verwendbar als Modifier**\ ja **Beispiel mit Text** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= len("abc def. XYZ") }} ``` **Ausgabe** (Anzahl der Zeichen) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 12 ``` **Beispiel mit Auflistung** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= len([1, 2, 3]) }} ``` **Ausgabe** (Anzahl der Einträge) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 3 ``` **Beispiel mit Datenobjekt** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= len({name: "Produkt", price: 12.99}) }} ``` **Ausgabe** (Anzahl der Schlüssel-Wert-Paare) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 2 ``` **Beispiel - Anzahl der Produkte in einer Kategorie anzeigen**\ Die Produkte einer Kategorie werden über [\$wsCategories.loadProducts()](/frontend/referenz/module/wscategories#\$wscategories-loadproducts) geladen (hier: 24 Produkte in der Kategorie). Mit `len` wird die Anzahl ermittelt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $products = $wsCategories.loadProducts("100-12345") }}

{{= len($products) }} Produkte gefunden

``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 24 Produkte gefunden ``` *** ### lower Die Funktion `lower` wandelt alle Buchstaben eines Textes in Kleinbuchstaben um. **Anwendungsbeispiel**\ Nutzbar, um z.B. Benutzereingaben, Gutscheincodes oder Produktkennungen einheitlich in Kleinschreibung darzustellen oder zu vergleichen. **Signatur**\ `lower(content)` **Parameter** * `content` - der Text, der in Kleinbuchstaben umgewandelt werden soll. **Verwendbar als Modifier**\ ja **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= lower("TOPSELLER") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} topseller ``` **Gegenstück**\ [upper](#upper) *** ### max Die Funktion `max` gibt den höchsten Wert aus einer Auflistung von Zahlen zurück. **Anwendungsbeispiel**\ Nutzbar, um z.B. den teuersten Preis innerhalb einer Variantenliste oder die höchste verfügbare Menge zu ermitteln. **Signatur**\ `max(list)` **Parameter** * `list` - die Auflistung mit Zahlenwerten. **Verwendbar als Modifier**\ ja **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= max([5, 13, -1, 3, 2, -7, 12]) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 13 ``` **Beispiel - Höchsten Bestellwert aus der Bestellhistorie ermitteln**\ Die letzten Bestellungen eines Kunden werden über `$wsOrderHistory.loadList()` geladen. Jede Bestellung enthält u. a. das Feld `order.total` (Gesamtpreis). Die geladenen Bestellwerte werden mit [push](#push) in einer eigenen Auflistung gesammelt und anschließend mit `max` der höchste Wert ermittelt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myOrders = $wsOrderHistory.loadList() }} {{ var $myTotals = [] }} {{ for $myOrder in $myOrders }} {{ push($myTotals, $myOrder.order.total) }} {{ /for }}

Ihre höchste Bestellung: {{= max($myTotals) | currency }} €

``` **Ausgabe** (bei Bestellwerten `49.90`, `129.00`, `89.95`): ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Ihre höchste Bestellung: 129,00 € ``` **Gegenstück**\ [min](#min) *** ### merge Die Funktion `merge` führt zwei Datenobjekte (Maps) zusammen. Die Einträge aus dem zweiten Objekt (`source`) werden in das erste Objekt (`target`) übernommen. Bei Listen werden die Einträge der zweiten Liste an die erste angehängt. Es wird kein neues Objekt erzeugt, das erste Objekt wird direkt verändert. Für Maps steht optional der Parameter `deep` zur Verfügung. Bei `deep=true` werden verschachtelte Maps ebenfalls zusammengeführt, anstatt überschrieben zu werden. **Anwendungsbeispiel**\ Nutzbar, um z.B. Standardwerte für die Produktanzeige mit produktspezifischen Werten zusammenzuführen. So können z.B. Standardtext oder Fallback-Bilder definiert werden, die nur dann zum Einsatz kommen, wenn ein Produkt keinen eigenen Wert hat. **Signatur**\ `merge(target, source[, deep=false])` **Parameter** * `target` - das Ziel-Objekt, in das die Einträge eingefügt werden. * `source` - das Quell-Objekt, dessen Einträge übernommen werden. * `deep` (optional) - nur für Maps. Bei `true` werden verschachtelte Maps ebenfalls zusammengeführt. **Verwendbar als Modifier**\ ja **Beispiel - Standardwerte mit produktspezifischen Daten zusammenführen** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $defaults = {"badge": "Neu", "shipping": "Standardversand"} }} {{ var $productData = {"badge": "Sale", "color": "rot"} }} {{= merge($defaults, $productData) }} ``` **Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {"badge": "Sale", "shipping": "Standardversand", "color": "rot"} ``` Wenn beide Objekte denselben Bezeichner (Schlüssel) enthalten, wird der Wert aus dem ersten Objekt durch den Wert aus dem zweiten Objekt überschrieben. **Beispiel - Produktdaten mit verschachtelten Standardwerten zusammenführen** (`deep merge`) Standardwerte für ein Produkt enthalten auch verschachtelte Bilddaten (`image`). Mit `deep=true` werden diese beim Zusammenführen nicht vollständig überschrieben, sondern ebenfalls zusammengeführt - sodass nur die tatsächlich vom Produkt gelieferten Bildpfade übernommen werden, fehlende aber durch den Standardwert erhalten bleiben. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $defaults = {"badge": "Neu", "shipping": "Standardversand", "image": {"normal": "noImageNormal.png", "thumb": "noImageThumb.png"}} }} {{ var $productData = {"badge": "Sale", "image": {"normal": "sneaker-normal.png"}} }} {{= merge($defaults, $productData, true) }} ``` **Ausgabe (das Thumbnail aus den Standardwerten bleibt erhalten, weil das Produkt keines mitliefert)** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {"badge": "Sale", "shipping": "Standardversand", "image": {"normal": "sneaker-normal.png", "thumb": "noImageThumb.png"}} ``` *** ### min Die Funktion `min` gibt den niedrigsten Wert aus einer Auflistung von Zahlen zurück. **Anwendungsbeispiel**\ Nutzbar, um z.B. den günstigsten Preis innerhalb einer Variantenliste oder den kleinsten Bestand zu ermitteln. **Signatur**\ `min(list)` **Parameter** * `list` - die Auflistung mit Zahlenwerten. **Verwendbar als Modifier**\ ja **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= min([5, 13, -1, 3, 2, -7, 12]) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} -7 ``` **Beispiel - Niedrigsten Bestellwert aus der Bestellhistorie ermitteln**\ Die letzten Bestellungen eines Kunden werden über [\$wsOrderHistory.loadList()](/frontend/referenz/module/wsorderhistory#\$wsorderhistory-loadlist) geladen. Jede Bestellung enthält u. a. das Feld `order.total` (Gesamtpreis). Die Bestellwerte werden mit [push](#push) in einer eigenen Auflistung gesammelt, anschließend wird mit `min` der niedrigste Wert ermittelt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myOrders = $wsOrderHistory.loadList() }} {{ var $myTotals = [] }} {{ for $myOrder in $myOrders }} {{ push($myTotals, $myOrder.order.total) }} {{ /for }}

Ihre niedrigste Bestellung: {{= min($myTotals) | currency }} €

``` **Ausgabe** (bei Bestellwerten `49.90`, `129.00`, `89.95`): ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Ihre niedrigste Bestellung: 49,90 € ``` **Gegenstück**\ [max](#max) *** ### preparedFormat Die Funktion `preparedFormat` formatiert eine Zahl hinsichtlich Dezimaltrennzeichen und Nachkommastellen, basierend auf einem [im Shop hinterlegten Format](/konfiguration/general-allgemeine-shopeinstellungen#12-general-numberformat-zahlen-und-preisformatierung). **Anwendungsbeispiel** Nutzbar, um z.B. Mengenangaben, Gewichte oder andere Zahlenwerte shopgerecht darzustellen. **Signatur**\ `preparedFormat(number, formatName)` **Parameter** * `number` - Die Zahl, die formatiert werden soll. * `name` - Name des im Shop konfigurierten Formats (z.B. `“amount”`). **Verwendbar als Modifier**\ ja **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= preparedFormat(3.5, "amount") }} ``` **Ausgabe** (`amount` formatiert hier auf ganze Zahlen) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 4 ``` **Beispiel - Produktgewicht formatiert ausgeben**\ Das Gewicht eines Produkts ist im Feld `$myProduct.custom.weight` als Dezimalzahl gespeichert (hier: `2.300000`). Mit `preparedFormat` wird es gemäß dem im Shop hinterlegten Format `"weight"` ausgegeben. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $weight = $myProduct.custom.weight }}

Gewicht: {{= preparedFormat($weight, "weight") }} kg

``` **Ausgabe** (bei einem Gewicht von `2.300000` und Format `"weight"` mit einer Nachkommastelle): ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Gewicht: 2,3 kg ``` *** ### push Die Funktion `push` fügt ein neues Element am Ende einer bestehenden Liste hinzu und gibt die neue Anzahl der Einträge in der Auflistung zurück. Die Liste wird dabei direkt verändert, es wird keine neue Liste erzeugt. **Anwendungsbeispiel**\ Nutzbar, um z.B. in einer Schleife gezielt Einträge zu sammeln, etwa gefilterte Produkte, Fehlermeldungen oder dynamisch zusammengestellte Ausgabelisten. **Signatur**\ `push(list, element)` **Parameter** * `list` - Die Auflistung, an die das neue Element angehängt werden soll. * `element` - Der Wert, der hinzugefügt werden soll. **Verwendbar als Modifier**\ ja **Beispiel - Element hinzufügen** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myWishlist = ["ART-100", "ART-205"] }} {{ push($myWishlist, "ART-310") }} {{= $myWishlist }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ["ART-100", "ART-205", "ART-310"] ``` **Beispiel - Rückgabewert nutzen** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myWishlist = [] }} {{ push($myWishlist, "ART-100") }} {{ var $amount = push($myWishlist, "ART-205") }} {{= $amount }} ``` **Ausgabe (Anzahl der Einträge nach dem Hinzufügen)** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 2 ``` **Beispiel - Produkte einer Kategorie laden und Produkte aus einer anderen Kategorie ergänzen**\ Die Produkte einer Kategorie werden über `$wsCategories.loadProducts()` als Auflistung geladen. Mit `push` können Produkte aus einer zweiten Kategorie an die Liste angehängt werden - z.B. um Cross-Selling-Artikel in die Ausgabe aufzunehmen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProducts = $wsCategories.loadProducts("100-12345") }} {{ var $myCrossSelling = $wsCategories.loadProducts("100-99999") }} {{ for $item in $myCrossSelling }} {{ push($myProducts, $item) }} {{ /for }} {{ for $product in $myProducts }}

{{= $product.name }}

{{ /for }} ``` Die Auflistung `$myProducts` enthält nun alle Produkte der ersten Kategorie plus die Produkte aus der Cross-Selling-Kategorie. *** ### random Die Funktion `random` erzeugt einen Zufallswert. **Anwendungsbeispiel**\ Nutzbar, um z.B. zufällige Gutscheincodes zu Erzeugen. **Hinweis**\ Die Funktion ist geplant, wird aber momentan noch nicht unterstützt. *** ### range Die Funktion `range` erzeugt eine Auflistung von aufeinanderfolgenden ganzen Zahlen - vom Startwert bis zum Endwert. Standardmäßig wird in Einserschritten gezählt. Bei absteigenden Reihen muss eine negative Schrittweite angegeben werden. **Anwendungsbeispiel**\ Nutzbar, um z.B. Seitenumbrüche (Pagination), Mengenwähler oder nummerierte Ausgaben im Template zu erzeugen. **Signatur**\ `range(start, stop[, step=1])` **Parameter** * `start` - Startwert der Zahlenreihe. * `stop` - Endwert der Zahlenreihe. * `step` (optional) - Schrittweite (Standard: 1). Für absteigend zählende Reihen einen negativen Wert verwenden. **Verwendbar als Modifier**\ nein **Beispiel für eine aufsteigende Reihe** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= range(1, 5) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [1, 2, 3, 4, 5] ``` **Beispiel für eine absteigende Reihe** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= range(10, 2, -2) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [10, 8, 6, 4, 2] ``` *** ### raw Die Funktion `raw` gibt einen Wert ohne automatische Bereinigung von HTML-Zeichen aus, sodass enthaltener HTML-Code vom Browser als Formatierung interpretiert wird, statt als reiner Text an gezeigt zu werden. **Anwendungsbeispiel**\ Nutzbar, um z.B. formatierte Produktbeschreibungen oder CMS-Inhalte mit HTML-Markup unverändert im Shop darzustellen. **Hinweis**\ Die Funktion ist geplant, wird aber momentan noch nicht unterstützt. *** ### replace Die Funktion `replace` ersetzt in einem Text alle Vorkommen eines Suchbegriffs durch einen anderen Text. **Anwendungsbeispiel**\ Nutzbar, um z.B. interne Bezeichnung für die Anzeige im Shop leserlicher zu machen. **Signatur**\ `replace(string, search, replace)` **Parameter** * `content` - Der Ausgangstext. * `search` - Der Text, der gesucht und ersetzt werden soll. * `replace` - Der Text, der stattdessen eingesetzt werden soll. **Verwendbar als Modifier**\ ja **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= replace("webbuy", "buy", "sale") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} websale ``` *** ### reverse Die Funktion `reverse` kehrt die Reihenfolge der Zeichen in einem Text oder der Einträge in einer Auflistung um. **Anwendungsbeispiel**\ Nutzbar, um z.B. eine bestehende Sortierung umzukehren oder Einträge in umgekehrter Reihenfolge auszugeben (z.B. neueste Einträge zuerst). **Hinweis**\ Die Funktion ist geplant, wird aber momentan noch nicht unterstützt. *** ### round Die Funktion `round` rundet eine Zahl kaufmännisch auf oder ab. Optional kann die gewünschte Anzahl an Nachkommastellen angegeben werden. Ohne Angabe wird auf eine ganze Zahl gerundet. **Anwendungsbeispiel**\ Nutzbar, um z.B. berechnete Zwischenwerte, Gewichte oder Mengen kaufmännisch gerundet im Template anzuzeigen. **Signatur**\ `round(number[, precision=0])` **Parameter** * `number` - Die Zahl, die gerundet werden soll. * `precision` (optional) - Gewünschte Anzahl an Nachkommastellen (Standard: 0). **Verwendbar als Modifier**\ ja **Beispiel ohne Nachkommastellen** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= round(3.1415) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 3.000000 ``` **Beispiel mit 2 Nachkommastellen** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= round(1.2345, 2) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 1.230000 ``` **Anzeige mit zwei Nachkommastellen** Der Parameter `precision` steuert die mathematische Rundung (auf wie viele Nachkommastellen der Wert gerundet wird). Die Ausgabe zeigt jedoch systembedingt immer bis zu sechs Nachkommastellen an (z.B: `1.230000` statt `1.23`). Um die Darstellung anzupassen (z.B. nur 2 sichtbare Nachkommastellen), wird `round` in Kombination mit [preparedFormat](#preparedformat) verwendet: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= round(1.2345, 2) | preparedFormat("name") }} ``` *** ### sort Die Funktion `sort` sortiert die Einträge einer Auflistung (List). Standardmäßig wird aufsteigend sortiert. Mit dem optionalen Parameter `reverse` kann die Sortierung aber auch umgekehrt werden. **Anwendungsbeispiel**\ Nutzbar, um z.B. Produktlisten, Varianten oder Filteroptionen alphabetisch oder nach Zahlenwert zu sortieren. **Signatur**\ `sort(list[, reverse=false])` **Parameter** * `list` - Die Auflistung, deren Einträge sortiert werden sollen. * `reverse`(optional) - Bei `true` wird absteigend sortiert. **Verwendbar als Modifier**\ ja **Beispiel mit Zahlen** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= sort([5, 2, 8, 1, 4]) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [1.0, 2.0, 4.0, 5.0, 8.0] ``` **Beispiel mit Texten** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= sort(["Hose", "Accessoire", "Jacke"]) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ["Accessoire", "Hose", "Jacke"] ``` **Beispiel - Preise absteigend sortieren** Wenn die Liste nur aus Zahlen besteht, werden alle Elemente nach der Sortierung den Typ `float` haben. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $prices = [49.90, 129.00, 19.95, 89.95] }} {{= sort($prices, true) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [129.000000, 89.950000, 49.900000, 19.950000] ``` **Beispiel - Verfügbare Farben eines Produkts alphabetisch sortieren**\ Die varianten-Daten eines Produkts werden über `$wsProducts.variantInfo()` geladen. Das Attribut “Farbe” enthält eine Auflistung von Optionen (hier: `Rot, Blau, Grün, Beige`). Da die Optionen als Objekte vorliegen (z.B. `{name: “Rot”}`), werden die Namen zunächst mit [push](#push) in einer eigenen Auflistung gesammelt. Anschließend werden sie mit `sort` alphabetisch sortiert und in einer Schleife ausgegeben. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myVariants = $wsProducts.variantInfo("100-12345") }} {{ var $colors = [] }} {{ for $myOption in $myVariants.variantAttributes.options }} {{ push($colors, $myOption.name) }} {{ /for }} {{ var $sortedColors = sort($colors) }} {{ for $color in $sortedColors }}
  • {{= $color }}
  • {{ /for }} ``` *** ### split Die Funktion `split` teilt einen Text anhand eines Trennzeichens in eine Auflistung (List) einzelner Einträge auf. **Anwendungsbeispiel**\ Nutzbar, um z.B. kommaseparierte Werte aus Produktdaten, Konfigurationen oder externen Quellen in einzelne Einträge zu zerlegen und getrennt zu verarbeiten. **Signatur**\ `split(content, separator)` **Parameter** * `content` - Der Text, der aufgeteilt werden soll. * `separator` - Das Trennzeichen, an dem der Text aufgeteilt wird. **Verwendbar als Modifier**\ ja **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= split("vegan,glutenfrei,laktosefrei,bio", ",") }} ``` **Ausgabe** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ["vegan", "glutenfrei", "laktosefrei", "bio"] ``` **Gegenstück**\ [join](#join) *** ### startswith Die Funktion `startswith` prüft, ob ein Text mit einer bestimmten Zeichenfolge beginnt und gibt `true` oder `false` zurück. **Anwendungsbeispiel**\ Nutzbar, um z.B. Artikelnummern anhand ihrer Anfangszeichen zu unterscheiden und im Template darauf zu reagieren, etwa um Produkte bestimmter Produktgruppen unterschiedlich darzustellen (z.B. alle Artikelnummern, die mit `“TKK”` beginnen, als Tiefkühlprodukte zu kennzeichnen). **Signatur**\ `startswith(str, prefix)` **Parameter** * `str` - Der Text, der geprüft werden soll. * `prefix` - Die Zeichenfolge, auf die am Textanfang geprüft wird. **Verwendbar als Modifier**\ ja **Beispiel mit einem Treffer** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= startswith("TKK-40210", "TKK") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} true ``` **Beispiel ohne Treffer** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= startswith("BKL-10050", "TKK") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} false ``` **Beispiel - Produkte anhand der Artikelnummer einer Produktgruppe zuordnen** Die Artikelnummer eines Produkts steht im Feld `itemNumber` (hier: `“TKK-40210”`). Artikelnummern, die mit `“TKK”` beginnen, gehören zur Produktgruppe Tiefkühlware. Mit `startswith` wird dies geprüft und ein entsprechendes Badge angezeigt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProduct = $wsProducts.load("100-12345") }} {{ if (startswith($myProduct.itemNumber, "TKK")) }} Tiefkühlprodukt {{ /if }} ``` **Ausgabe** (bei Artikelnummer `“TKK-40210”`) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Tiefkühlprodukt ``` *** ### static Die Funktion `static` erzeugt den vollständigen Pfad zu einer statischen Datei (z.B. JavaScript, CSS, Bilder). Standardmäßig liegen solche Dateien unter `media/themes/default` auf dem Server des Shops. **Anwendungsbeispiel**\ Nutzbar, um z.B. Pfade zu statischen Dateien im Template korrekt einzubinden - auch, wenn sich der Speicherort später ändert. **Signatur**\ `static(path)` **Parameter** * `path` - Pfad zur Datei, relativ zum Static-Verzeichnis des Shops. **Verwendbar als Modifier**\ nein **Beispiel**\ Statt eines fest eingetragenen Pfads: ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` wird empfohlen, `static` zu verwenden: ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` Durch die konsequente Nutzung von `static` kann der Speicherort der statischen Dateien jederzeit angepasst werden (z.B. auf einen Media-Server oder ein CDN), ohne dass die Templates geändert werden müssen. Bei Kategorie- oder Produktbildern wird `static` nicht benötigt - deren Pfade werden automatisch korrekt erzeugt. *** ### str Die Funktion `str` wandelt einen Wert in einen Text (String) um. Das Ergebnis sieht bei Zahlen zwar identisch aus, ist intern aber ein String - also kein Zahlenwert mehr, mit dem gerechnet werden könnte. Stattdessen kann der Wert danach mit textbasierten Funktionen wie `replace`, `startswith` oder `split` weiterverarbeitet werden. **Anwendungsbeispiel**\ Nutzbar, um z.B. eine Artikelnummer, die als Zahl vorliegt, in einen Text umzuwandeln, damit anschließend mit `startswith` geprüft werden kann, ob sie mit einer bestimmten Zeichenfolge beginnt. **Signatur**\ `str(value)` **Parameter** * `value` - Der Wert, der in Text umgewandelt werden soll. **Verwendbar als Modifier**\ ja **Beispiel mit ganzer Zahl** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= str(42) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "42" ``` **Beispiel mit Dezimalzahl** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= str(12.99) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "12.99" ``` *** ### striphtml Die Funktion `striphtml` entfernt alle HTML-Formatierungen (Tags) aus einem Text und gibt nur den reinen Textinhalt zurück. **Anwendungsbeispiel**\ Nutzbar, um z.B. HTML-formatierte Produktbeschreibungen als reinen Text auszugeben. **Signatur**\ `striphtml(content)` **Parameter** * `content` - Der Text, aus dem die HTML-Formatierungen entfernt werden sollen. **Verwendbar als Modifier**\ ja **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= striphtml("

    Unser Topseller im Shop!

    ") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Unser Topseller im Shop! ``` *** ### take Die Funktion `take` gibt die ersten Zeichen eines Textes oder die ersten Einträge einer Auflistung zurück. **Anwendungsbeispiel**\ Nutzbar, um z.B. nur die ersten Zeichen eines Produktnamens oder die ersten Einträge einer Produktliste anzuzeigen. **Signatur**\ `take(content, count)` **Parameter** * `content` - Der Text oder die Auflistung, aus der die ersten Elemente entnommen werden sollen. * `count` - die Anzahl der Zeichen bzw. Einträge, die vom Anfang genommen werden. **Verwendbar als Modifier**\ ja **Beispiel mit Text** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= take("websale", 3) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} web ``` **Beispiel mit Auflistung** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= take([1, 2, 3, 4, 5], 3) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [1, 2, 3] ``` **Beispiel - Nur die ersten 4 Produkte einer Kategorie anzeigen**\ Die Produkte einer Kategorie werden über [\$wsCategories.loadProducts()](/frontend/referenz/module/wscategories#\$wscategories-loadproducts) als Auflistung geladen (hier: `24 Produkte`). Mit `take` werden in diesem Beispiel nur die ersten 3 Einträge entnommen und in einer Schleife als Teaser ausgegeben. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProducts = $wsCategories.loadProducts("100-12345") }} {{ var $myTopProducts = take($myProducts, 3) }} {{ for $product in $myTopProducts }} {{= $product.name }} {{ /for }} ``` **Ausgabe** (bei Produkten `"Sneaker Classic"`, `"Laufschuh Pro"`, `"Sandale Sport"`, `"Wanderstiefel"`, …) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Sneaker Classic Laufschuh Pro Sandale Sport ``` **Gegenstück**\ [takelast](#takelast) *** ### takelast Die Funktion `takelast` gibt die letzten Zeichen eines Textes oder die letzten Einträge einer Auflistung zurück. **Anwendungsbeispiel**\ Nutzbar, um z.B. die letzten Zeichen einer Bestellnummer oder die letzten Einträge einer Liste gezielt anzuzeigen. **Signatur**\ `takeLast(content, count)` **Parameter** * `content` - Der Text oder die Auflistung, aus der die letzten Elemente entnommen werden sollen. * `count` - Die Anzahl der Zeichen bzw. Einträge, die vom Ende genommen werden. **Verwendbar als Modifier**\ ja **Beispiel mit Text** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= takeLast("12345", 2) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 45 ``` **Beispiel mit Auflistung** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= takeLast([1, 2, 3, 4, 5], 2) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [4, 5] ``` **Beispiel - Die letzten 2 Ebenen des Breadcrumb-Pfads anzeigen**\ Der Kategoriepfad (`Breadcrumb`) wird über [\$wsCategories.loadPath()](/frontend/referenz/module/wscategories#\$wscategories-loadpath) als Auflistung geladen (hier: 4 Ebenen). Mit `takeLast` werden nur die letzten 2 Einträge entnommen - z.B. um in einer Unternavigation nur die aktuelle und die übergeordnete Kategorie anzuzeigen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $breadcrumb = $wsCategories.loadPath($category.id) }} {{ var $lastTwo = takeLast($breadcrumb, 2) }} {{ for $cat in $lastTwo }} {{= $wsViews.url('Category', {id: $cat.id}) }}">{{= $cat.name }} {{ /for }} ``` **Ausgabe** (bei einem Pfad “Startseite → Damen → Schuhe → Sneaker”): ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Schuhe Sneaker ``` **Gegenstück**\ [take](#take) *** ### trim Die Funktion `trim` entfernt überflüssige Leerzeichen am Anfang und Ende eines Textes. **Anwendungsbeispiel**\ Nutzbar, um z.B. Benutzereingaben, importierte Produktdaten oder externe Werte vor der Weiterverarbeitung von ungewollten Leerzeichen zu bereinigen. **Hinweis**\ Die Funktion ist geplant, wird aber momentan noch nicht unterstützt. *** ### type Die Funktion `type` Gibt den Datentyp eines Wertes als Text zurück - also z. B. ob es sich um einen Text (`string`), eine ganze Zahl (`int`), eine Dezimalzahl (`float`), eine Auflistung (`list`) oder ein Datenobjekt (`map`) handelt. **Anwendungsbeispiel**\ Nutzbar, um z.B. auf Fehlersuche zu gehen (Debugging) oder um im Template zu prüfen, ob ein Wert den erwarteten Typ hat, bevor er weiterverarbeitet wird. **Signatur**\ `type(object)` **Parameter** * `object` - Der Wert, dessen Datentyp ermittelt werden soll. **Verwendbar als Modifier**\ ja **Beispiel anhand eines Textes** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= type("Websale") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} String ``` **Beispiel anhand einer Kommazahl** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= type(1.27) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Float ``` *** ### unixToIso Die Funktion `unixToIso` wandelt eine Unix-Zeit (Anzahl der Sekunden seit dem 1. Januar 1970, UTC) in einen Zeitstempel im ISO-8601-Format um. **Anwendungsbeispiel**\ Nutzbar, um z.B. eine von einem externen System gelieferte Unix-Zeit in das Shop übliche ISO-8601-Format zu bringen, das anschließend mit [dateFmt](https://dokumentation.websale.de/frontend/referenz/funktionen#datefmt) formatiert werden kann. **Signatur**\ `unixToIso(timestamp)` **Parameter** * `timestamp` - Unix-Zeit (Anzahl der Sekunden seit dem 1. Januar 1970, UTC). **Verwendbar als Modifier**\ ja **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= unixToIso(1520767211) }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 2018-03-11T11:20:11.000Z ``` **Gegenstück**\ [isoToUnix](https://dokumentation.websale.de/frontend/referenz/funktionen#isotounix) *** ### upper Die Funktion `upper` wandelt alle Buchstaben eines Textes in Großbuchstaben um. **Anwendungsbeispiel**\ Nutzbar, um z.B. Gutscheincodes, Versandarten oder Überschriften einheitlich und in Großschreibung darzustellen. **Signatur**\ `upper(content)` **Parameter** * `content` - Der Text, der in Großbuchstaben umgewandelt werden soll. **Verwendbar als Modifier**\ ja **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= upper("Topseller") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} TOPSELLER ``` **Gegenstück**\ [lower](#lower) *** ## Modifier Viele Funktionen können alternativ auch als [Modifier (Filter)](/frontend/referenz/modifiers#modifiers) in der Filterschreibweise verwendet werden. Dabei steht der erste Parameter links vom Pipe-Operator `|`, weitere Parameter werden in Klammern angegeben. Alternativ kann eine Funktion auch mit dem Filter-Operator | (pipe) notiert werden (= Filterschreibweise). Dabei steht der erste Parameter links vom Operator. **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= "webbuy" | replace("buy", "sale") }} ``` **Ausgabe** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} websale ``` # Kontrollstrukturen Source: https://dokumentation.websale.de/frontend/referenz/kontrollstrukturen Kontrollstrukturen und Boolean-Werte: Wahrheitswerte true und false sowie Bedingungen für die Steuerung von Template-Ausgaben einsetzen. ## Boolean/Bool (true/false) Ein Bool ist ein Wahrheitswert und kann nur *true* (wahr) oder *false* (falsch) sein. | | | | -------- | ------------------------------------------- | | `true` | Wahrheitswert true | | `false` | Wahrheitswert false | | `"true"` | kein Wahrheitswert (falsche Syntax: String) | Boolesche Werte werden meistens in Kombination mit Vergleichsoperatoren erzeugt. Wenn man beispielsweise einen Wert mit einem anderen vergleicht, ist das Ergebnis entweder wahr oder falsch. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $quantity == 1 }}     Wird angezeigt, wenn der Wert der Variable $quantity gleich 1 ist. {{ /if }} ``` ## truthy und falsy Nicht nur Werte vom Datentyp Bool enthalten einen Wahrheitswert. Objekte aller anderen Datentypen haben ebenfalls eine Werte-Eigenschaft, die man als *truthy* oder *falsy* bezeichnet. In Zusammenhang mit logischen Operatoren und Verzweigungen ist es wichtig zu wissen, wann ein Wert als wahr oder falsch angesehen wird. Hier eine Auflistung aller Werte die *falsy* sind und deshalb als *false* behandelt werden: ▪*null*, der Wert des Datentyps Null ▪*false* ▪die Zahl 0 (*Integer*) oder 0.0 (*Float*) ▪ein leerer *String " "* ▪eine leere *List \[ ]* ▪eine leere *Map* Alle anderen Werte werden als *truthy* behandelt. ## Boolean konvertieren Es können andere Basistypen in Boolean konvertiert werden ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} String: {{= bool(" ")}} // true String: {{= bool("")}} // false Integer: {{= bool(1) }} // true Integer: {{= bool(0) }} // false Float: {{= bool(1.0) }} // true Float: {{= bool(0.0) }} // false ``` # Loops Source: https://dokumentation.websale.de/frontend/referenz/loops Schleifen und Verzweigungen in Templates: if, elseif, else, switch sowie foreach für die bedingte und wiederholte Template-Ausgabe nutzen. Mit Hilfe von Kontrollstrukturen kannst Du die Ausgabe abhängig machen von bestimmten Bedingungen. Man unterscheidet zwischen Verzweigungen mit *if* oder *switch* und der *foreach*-Schleife. ## if-Verzweigung Mit einer *if*-Verzweigung werden eine oder mehrere Bedingungen geprüft. Je nachdem, welche Bedingung als erstes ein *true* zurückgibt, wird dieser Zweig angezeigt und die restlichen werden ignoriert. Eine *if*/*elseif*/*else*-Verzweigung muss immer aus einem *if*-Zweig und optional beliebig viele *elseif*-Zweige bestehen sowie optional einem einzigen *else*-Zweig. Eine Verzweigung wird mit *if* eingeleitet und durch */if* abgeschlossen. *elseif*- und *else*-Zweige werden dagegen nicht explizit geschlossen. Das folgende Beispiel zeigt die unterschiedlichen Anredeformen, wenn Bestandskunden im Shop angemeldet sind. Auf dem Template sei eine Variable *\$geschlecht* definiert, die sich das entsprechende Geschlecht aus den Kundendatensätzen holt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $geschlecht == "männlich" }} Sehr geehrter Herr {{= $customer.lastName }}, {{ elseif $geschlecht == "weiblich" }} Sehr geehrte Frau {{= $customer.lastName }}, {{ else }} Sehr geehrte Damen und Herren, {{ /if }} ``` ## switch-Verzweigung Alternativ zu *if*-Verzweigungen kannst Du auch *switch*, *case* und *default* verwenden. Mit *switch* leitest Du die Verzweigung ein und gibst an, welches Feld geprüft werden soll. Hinter *case* schreibst Du ohne *==* die unterschiedlichen Werte und *default* entspricht *else*. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ switch $geschlecht }} {{ case "männlich" }} Sehr geehrter Herr {{= $customer.lastName }}, {{ case "weiblich" }} Sehr geehrte Frau {{= $customer.lastName }}, {{ default }} Sehr geehrte Damen und Herren, {{ /switch }} ``` ## foreach-Schleife Eine *foreach*-Schleife dient dazu, Codeabschnitte mehrfach zu wiederholen (*iterieren*). Die Schleife wird mit *foreach* eingeleitet und mit */foreach* geschlossen. Der umschlossene Bereich wird für jedes Element des iterierbaren Objekts einmal ausgeführt. Mit jedem Durchlauf wird das aktuelle Element des iterierbaren Objekts der sogenannten Laufvariable (im Beispiel unten *\$product)* ohne *var* zugewiesen. Im folgenden Beispiel enthält *\$productList* eine List mit 3 Elementen. Mit jedem Durchlaufen der Schleife wird das jeweilige Element mit den HTML-Tags ausgegeben. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $productList = ["Hemd", "Bluse", "Hose"] }} {{ foreach $product in $productList }}
    Produkt: {{= $product }}
    {{ /foreach }} ``` Es wird folgender HTML-Quellcode erzeugt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
    Produkt: Hemd
    Produkt: Bluse
    Produkt: Hose
    ``` Das Iterieren mit einer *foreach*-Schleife ist mit *Strings*, *Lists* und *Maps* möglich. Die *foreach*-Schleife ist der einzige Schleifentyp der Template Engine. Andere Schleifen wie *for*, *while* oder *do-while* gibt es nicht. ### Schleifenzähler Die Template Engine stellt innerhalb einer *foreach*-Schleife keine automatische Zählervariable bereit. Eine Variable wie `$loop.index` existiert nicht. Wenn Du die Position des aktuellen Elements benötigst, definierst Du vor der Schleife eine eigene Variable mit `var` und zählst sie am Ende jedes Durchlaufs hoch. Das folgende Beispiel fügt nach dem zweiten Produkt (also an dritter Stelle) einen Platzhalter in die Produktliste ein. Danach läuft die Schleife normal weiter. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $index = 0 }} {{ foreach $product in $productList }}
    Produkt: {{= $product }}
    {{ if $index == 1 }}
    {{ /if }} {{ var $index = $index + 1 }} {{ /foreach }} ``` Da der Zähler bei `0` startet, entspricht `$index == 1` dem zweiten Element. # Modifiers Source: https://dokumentation.websale.de/frontend/referenz/modifiers Modifiers (Filter) in der Template-Sprache: Werte bei der Ausgabe formatieren, Strings anpassen, Zahlen runden und Listen umwandeln. Diese Seite beschreibt die Grundlagen und Schreibweise von Modifiers. Modifiers (auch Filter genannt) werden verwendet, um Werte im Template direkt bei der Ausgabe oder Weiterverarbeitung zu verändern, zu formatieren oder zu prüfen – zum Beispiel Texte anpassen, Zahlen runden oder Listen umwandeln. *** ## Grundlagen & Schreibweise Modifiers werden nicht als eigenständiger Funktionsaufruf geschrieben, sondern auf einen bestehenden Wert angewendet. Ein Modifier verarbeitet immer den Wert, der links von ihm steht. Das Ergebnis kann direkt ausgegeben oder in einer Variablen gespeichert und später weiterverwendet werden. Modifiers werden mit dem Pipe-Operator `|` an einen Wert „angehängt“: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= | }} ``` Wenn ein Modifier zusätzliche Parameter benötigt, werden diese in runden Klammern angegeben: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= | (, , ...) }} ``` ## Übersicht der Modifier Eine vollständige Liste aller verfügbaren Modifiers wird hier nicht separat geführt, da nahezu alle globalen Funktionen aus der Referenzseite [Funktionen](/frontend/referenz/funktionen) zusätzlich auch als Modifier verwendet werden können. ## Beispiele ### **Beispiel** `upper` Wert in Großbuchstaben ausgeben ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= "Sneaker Classic" | upper }} ``` \= ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} SNEAKER CLASSIC ``` ### **Beispiel** `replace` und `lower` Wert für URL/Slug vorbereiten (Leerzeichen ersetzen + Kleinschreibung) ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= "Sneaker Classic" | replace(" ", "-") | lower }} ``` \= ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} sneaker-classic ``` # Module - Übersicht Source: https://dokumentation.websale.de/frontend/referenz/module Übersicht der WEBSALE-Module wie $wsAccount, $wsBasket oder $wsProducts: Variablen und Methoden für die Template-Ausgabe von Shopdaten. Module sind von **WEBSALE** vorgegebene, global verfügbare Module (z. B. `$wsAccount`). Sie stellen Variablen (Eigenschaften) und Methoden bereit. In der Entwicklung werden sie teilweise auch als `View-Module` bezeichnet, da sie primär für die Ausgabe (Leseseite) verwendet werden. Mit diesen Modulen stehen Shopdaten für die Template-Ausgabe zur Verfügung, z. B. zu Produkten, Kategorien oder Käuferdaten. Eigene Module können nicht erstellt oder erweitert werden. *** ## Schreibweise & Zugriff * **Schreibweise:** `$ws` (z. B. `$wsAccount`, `$wsBasket`, `$wsProduct`) * Module enthalten Variablen (Eigenschaften) und Methoden * Der Zugriff erfolgt über den Punkt-Operator (`.`), z. B. auf Eigenschaften oder Methoden eines Moduls * Datenfelder und Funktionen werden einheitlich über `.` angesprochen **Syntax-Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} $ws. ??? ``` Mehr Informationen zum [Datenzugriff](/frontend/datenzugriff-anzeige) finden Sie hier. *** ## Variablen & Methoden Ein Modul stellt in der Regel beides bereit: * Variablen (Eigenschaften) * Methoden ### Variablen (Eigenschaften) Über die Variablen liefert das Modul direkt den Wert, der direkt ausgelesen werden kann. **Beispiel - Gibt an, ob der Benutzer eingeloggt ist** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ = $wsAccount.isLoggedIn }} ``` ### Methoden Die Methoden führen den Aufruf für das Modul aus (z. B. Laden von Daten) und liefern ein Ergebnis zurück. **Beispiel - Lädt die Adresse mit der angegebenen Id** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ = $wsAccount.loadAddress(addressId) }} ``` Viele Module liefern strukturierte Daten (z. B. „Maps“/Objekte). Auf deren Felder wird am übersichtlichsten über benutzerdefinierte Variablen zugegriffen, die einmalig im Template belegt wird. **Beispiel - Laden von den Daten des Produktes mit der ID 123456** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myVariable = $wsProducts.load(productId) }} ``` Über die benutzerdefinierte Variable `$myVariable` erfolgt der Zugriff auf einzelne Eigenschaften über `$myVariable.`: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ = $myVariable.name }} {{ = $myVariable.descr }} ``` Variablen- und Methodenaufrufe können nicht beliebig verkettet werden. Der folgende Aufruf ist daher nicht möglich: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ $wsAccount.loadAddress(addressId).isLoggedIn }} ``` *** ## Verfügbare Module Hier finden Sie eine Übersicht aller Module, die im WEBSALE Shop grundsätzlich verfügbar sind: * [\$wsAccount](/frontend/referenz/module/wsAccount) * [\$wsActions](/frontend/referenz/module/wsactions) * [\$wsAsse](/frontend/referenz/module/wsasse) * [\$wsBasket](/frontend/referenz/module/wsbasket) * [\$wsCategories](/frontend/referenz/module/wscategories) * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [\$wsCmsPage](/frontend/referenz/module/wscmspage) * [\$wsComputopHosted](/frontend/referenz/module/wscomputophosted) * [\$wsConfig](/frontend/referenz/module/wsconfig) * [\$wsConsent](/frontend/referenz/module/wsconsent) * [\$wsCookies](/frontend/referenz/module/ws-cookie-browser-cookie) * [\$wsDirectOrder](/frontend/referenz/module/wsdirectorder) * [\$wsEmails](/frontend/referenz/module/wsemails) * [\$wsExternalData](/frontend/referenz/module/wsexternaldata) * [\$wsForm](/frontend/referenz/module/wsform) * [\$wsInventory](/frontend/referenz/module/wsinventory) * [\$wsLastSeenProducts](/frontend/referenz/module/wslastseenproducts) * [\$wsMaintenance](/frontend/referenz/module/wsmaintenance) * [\$wsNavigation](/frontend/referenz/module/wsnavigation) * [\$wsNewsletter](/frontend/referenz/module/wsnewsletter) * [\$wsOptIn](/frontend/referenz/module/wsoptin) * [\$wsOrderHistory](/frontend/referenz/module/wsorderhistory) * [\$wsPayPalCheckout](/frontend/referenz/module/wspaypalcheckout) * [\$wsPayPalPlus](/frontend/referenz/module/wspaypalplus) * [\$wsProducts](/frontend/referenz/module/wsproducts) * [\$wsProductRating](/frontend/referenz/module/wsproductrating) * [\$wsSecurity](/frontend/referenz/module/wssecurity) * [\$wsSession](/frontend/referenz/module/wssession) * [\$wsShipTrack](/frontend/referenz/module/wsshiptrack) * [\$wsStore](/frontend/referenz/module/wsstore) * [\$wsStores](/frontend/referenz/module/wsstores) * [\$wsStripe](/frontend/referenz/module/wsstripe) * [\$wsSubshop](/frontend/referenz/module/wssubshop) * [\$wsTestMode](/frontend/referenz/module/wstestmode) * [\$wsViews](/frontend/referenz/module/wsviews) * [\$wsVoucher](/frontend/referenz/module/wsvoucher) * [\$wsWatchList](/frontend/referenz/module/wswatchlist) *** ## Aktionen `$wsActions` Parallel zu den Modulen gibt es Aktionen\*\*,\*\* die mit `$wsActions` beginnen. Während Module Zustände und Daten anzeigen/auslesen, sind Aktionen die Gegenrichtung: Sie dienen dazu, Daten zu erstellen, zu ändern oder zu löschen – typischerweise ausgelöst durch eine Benutzerinteraktion (z. B. Link, Button, Formular). Mehr Informationen dazu finden Sie unter [Referenz](/frontend/referenz) → [Aktionen](/frontend/referenz/aktionen) *** ## Weiterführende Links * [Datenzugriff + Anzeige](/frontend/datenzugriff-anzeige) * [Aktionen](/frontend/referenz/aktionen) # $wsCookie - Browser-Cookies Source: https://dokumentation.websale.de/frontend/referenz/module/ws-cookie-browser-cookie Modul $wsCookie zum Lesen, Setzen, Aktualisieren und Löschen einzelner Browser-Cookies im Template, z.B. für Darkmode oder Begrüßung. Mithilfe des `$wsCookie`-Moduls lesen, setzen, aktualisieren und löschen Sie [Browser-Cookies](/glossar#cookie) direkt im Template. Cookies speichern pro Besucher Informationen über mehrere Seitenaufrufe hinweg, zum Beispiel eine gewählte Darstellungsvariante, eine persönliche Begrüßung oder ein gemerktes Einverständnis. Auf dieser Seite geht es nur um das Lesen und Schreiben der Cookies selbst. Wie Sie die [Einwilligung](/glossar#consent) des Nutzers prüfen, ist in [\$wsConsent](/frontend/referenz/module/wsconsent) beschrieben. Hinweis: Das Setzen von Cookies kann je nach Art (technisch notwendig vs. Marketing/Tracking) eine Einwilligung des Nutzers erfordern. Prüfen Sie mit [\$wsConsent.checkAllowed()](/frontend/referenz/module/wsconsent#\$wsconsent-checkallowed) die Zustimmung, bevor Sie nicht-notwendige Cookies setzen. *** ## Grundkonzept Cookies folgen immer demselben Ablauf: **Setzen → Lesen → Reagieren.** \ Bevor Sie einen Cookie lesen können, muss er zuerst gesetzt werden. Gesetzt wird ein Cookie immer durch ein Ereignis. Typische Auslöser sind: * eine Benutzeraktion (Klick auf einen Toggle oder Link), * ein Zustand (der Kunde loggt sich ein), * eine Abhängigkeit (ein bestimmtes Kundendatenfeld ist vorhanden), * der Einstiegsweg (Aufruf über einen [Kampagnen-Link](/glossar#kampagnen-link) oder [Referrer](/glossar#referrer)). Beim nächsten Seitenaufruf lesen Sie den Wert wieder aus und reagieren darauf, etwa mit einer anderen Darstellung oder einer persönlichen Begrüßung. Wichtig zum Zeitpunkt der Ausführung: \ Der [Template-Code](/glossar#template-code) wird beim Seitenaufbau ausgeführt, nicht beim Klick. Ein Cookie wird also nicht im Moment des Klicks gesetzt, sondern erst dann, wenn der Klick eine neue Anfrage auslöst und das Template dabei erneut ausgeführt wird. Planen Sie das Setzen deshalb immer entlang eines Seitenaufrufs ein. ### Namensschema (gilt für alle Methoden) Der Shop benennt eigene Cookies automatisch um, und zwar nach dem Schema `wsvx__cookie`. Aus `setCookie("test", …)` im Shop `example` wird im Browser das Cookie `wsvx_example_cookietest`. In den Methoden arbeiten Sie immer nur mit dem kurzen Namen (`test`), das Präfix ergänzt der Shop selbst. So vermeiden Sie Konflikte mit anderen Cookies. Setzen und Lesen verwenden dasselbe Schema. Ein mit `setCookie("test", …)` gesetztes Cookie können Sie also direkt mit `getCookie("test")` wieder auslesen, ohne sich um den langen Namen kümmern zu müssen. **Ausnahme: Extern gesetzte Cookies**\ Cookies, die nicht vom Shop gesetzt wurden (z.B. über eigenes JavaScript, ein Drittanbieter-Tool oder ein Cookie-Banner), behalten ihren Original-Namen. Das automatische Schema würde hier ins Leere greifen. Wenn Sie ein solches Cookie auslesen möchten, übergeben Sie bei [getCookie](/frontend/referenz/module/ws-cookie-browser-cookie#wscookie-getcookie) die Option `keepNameAsIs: true`, damit der Name unverändert verwendet wird. Zum Setzen, Aktualisieren oder Löschen ist diese Option nicht vorgesehen, da externe Cookies in der Regel von dem Tool verwaltet werden, das sie gesetzt hat. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsCookie` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsCookie | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "deleteCookie": "ƒ()", "getCookie": "ƒ()", "setCookie": "ƒ()", "updateCookie": "ƒ()" } ``` Anmerkung: `"ƒ()"` kennzeichnet eine Funktion. **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ---------------- | ---------------- | -------------------------------------------------- | | `getCookie()` | string | Liest den Wert eines Cookies anhand seines Namens. | | `setCookie()` | – | Setzt ein neues Cookie. | | `updateCookie()` | string | Aktualisiert den Wert eines bestehenden Cookies. | | `deleteCookie()` | – | Löscht ein Cookie anhand seines Namens. | *** ## Templates Alle vier Methoden sind Template-Funktionen und stehen in jedem `.htm`-Template zur Verfügung. Den typischen Ablauf (Setzen → Lesen → Reagieren) beschreibt der Abschnitt [Grundkonzept](#grundkonzept). *** ## Variablen Für `$wsCookie` stehen keine Variablen zur Verfügung. *** ## Methoden ### \$wsCookie.getCookie() Liest den Wert eines Cookies anhand seines Namens. **Signatur**\ `$wsCookie.getCookie(name, [options])` **Rückgabe**\ `string` – Wert des Cookies. Der Wert ist leer, wenn kein Cookie mit diesem Namen existiert. **Parameter** | **Name** | **Typ** | **Pflicht** | **Standard** | **Beschreibung** | | --------- | ------- | ----------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | ja | – | Kurzer Name des Cookies, ohne Präfix. | | `options` | map | nein | – | `keepNameAsIs` (bool) – verwendet den Namen unverändert, ohne das automatische Schema.
    Nötig für extern gesetzte Cookies (siehe [Grundkonzept](#namensschema-gilt-für-alle-methoden)). | **Beispiel,** das eine gespeicherte Darstellungsvariante liest. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $currentTheme = $wsCookie.getCookie("wsThemeColor") }} ``` ### \$wsCookie.setCookie() Setzt ein neues Cookie. **Signatur**\ `$wsCookie.setCookie(name, value, [age])` **Rückgabe**\ – (kein Rückgabewert) **Parameter** | **Name** | **Typ** | **Pflicht** | **Standard** | **Beschreibung** | | -------- | ----------------------------------- | ----------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | ja | – | Kurzer Name des Cookies, ohne Präfix. | | `value` | string, int, float, list, map, bool | ja | – | Wert des Cookies. Komplexe Werte (list, map) werden intern automatisch als [JSON](/glossar#json) gespeichert. | | `age` | int | nein | Session | Gültigkeitsdauer in Sekunden. Ohne Angabe wird ein [Session-Cookie](/glossar#session-cookie) gesetzt, das am Ende der Browser-Sitzung verfällt. Maximal 10 Jahre. Beispiel: `31536000` = 365 Tage. | **Beispiel,** das eine Darstellungsvariante setzt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ $wsCookie.setCookie("wsThemeColor", "dark") }} ``` **Beispiel,** das ein Cookie mit einer Gültigkeitsdauer von 365 Tagen setzt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ $wsCookie.setCookie("welcomeBackName", $wsAccount.displayName, 31536000) }} ``` ### \$wsCookie.updateCookie() Aktualisiert den Wert eines bestehenden Cookies. **Signatur**\ `$wsCookie.updateCookie(name, value)` **Rückgabe**\ `string` – neuer Wert des Cookies. **Parameter** | **Name** | **Typ** | **Pflicht** | **Standard** | **Beschreibung** | | -------- | ----------------------------------- | ----------- | ------------ | ------------------------------------- | | `name` | string | ja | – | Kurzer Name des Cookies, ohne Präfix. | | `value` | string, int, float, list, map, bool | ja | – | Neuer Wert des Cookies. | **Beispiel,** das eine Darstellungsvariante aktualisiert. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ $wsCookie.updateCookie("wsThemeColor", "light") }} ``` ### \$wsCookie.deleteCookie() Löscht ein Cookie anhand seines Namens. Intern wird die Lebensdauer dabei auf `-1` gesetzt, wodurch der Browser das Cookie sofort verwirft. **Signatur**\ `$wsCookie.deleteCookie(name)` **Rückgabe**\ – (kein Rückgabewert) **Parameter** | **Name** | **Typ** | **Pflicht** | **Standard** | **Beschreibung** | | -------- | ------- | ----------- | ------------ | ------------------------------------- | | `name` | string | ja | – | Kurzer Name des Cookies, ohne Präfix. | **Beispiel,** das ein gesetztes Cookie löscht. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ $wsCookie.deleteCookie("wsThemeColor") }} ``` *** ## Aktionen Für `$wsCookie` stehen keine Aktionen zur Verfügung. *** ## Beispiele Die folgenden Beispiele sind von einfachen zu komplexeren Fällen geordnet: vom Zustand über die Benutzeraktion und den Einstiegsweg bis hin zum extern gesetzten Cookie und einem vollständigen Conversion-Tracking, das ein externes Cookie mit einer Einwilligungsprüfung kombiniert. ### Persönliche Begrüßung (WelcomeBack-Cookie) Auslöser ist hier der Zustand "Login". Der Kunde wird beim Aufruf des Shops persönlich begrüßt, auch wenn er nicht eingeloggt ist, sofern er sich zuvor einmal eingeloggt hat. So bleibt eine persönliche Note erhalten, ohne dass der Kunde dauerhaft angemeldet sein muss. **Schritt 1: Cookie beim Login setzen** Sobald sich der Kunde eingeloggt hat, wird sein Anzeigename im Cookie gespeichert. Fehlt der Anzeigename oder ist er leer, wird die E-Mail-Adresse verwendet. Der dritte Parameter gibt die Gültigkeitsdauer in Sekunden an (hier 365 Tage), damit die Begrüßung über einen längeren Zeitraum erhalten bleibt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.isLoggedIn }} {{ var $welcomeName = $wsAccount.displayName }} {{ if not $welcomeName }} {{ $welcomeName = $wsAccount.email }} {{ /if }} {{ $wsCookie.setCookie("welcomeBackName", $welcomeName, 31536000) }} {{ /if }} ``` **Schritt 2: Begrüßung auf einer beliebigen Seite anzeigen** Auf einer beliebigen Seite, etwa der Startseite, lesen Sie den Namen aus und zeigen die entsprechende Begrüßung an. Wenn kein Cookie vorhanden ist, weil sich der Kunde beispielsweise nie eingeloggt hat oder das Cookie abgelaufen ist, wird nichts angezeigt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $name = $wsCookie.getCookie("welcomeBackName") }} {{ if $name }} Willkommen zurück, {{= $name }}! {{ /if }} ``` **Ergebnis**\ Wiederkehrende Kunden sehen ihre persönliche Begrüßung, bis das Cookie abläuft oder gelöscht wird. **Hinweis:** Dieses Cookie enthält personenbezogene Daten. Prüfen Sie die Einwilligung über [\$wsConsent.checkAllowed()](/frontend/referenz/module/wsconsent#\$wsconsent-checkallowed) und weisen Sie auf der Startseite auf die Cookie-Richtlinien hin. ### Darstellungsvariante (z. B. Darkmode) speichern Auslöser ist hier eine Benutzeraktion, nämlich ein Klick. Da WEBSALE nicht mit einem Theme-System arbeitet, müssen Sie eine Darstellungsvariante selbst erstellen. Dazu legen Sie die Wahl des Nutzers in einem Cookie ab und laden beim Seitenaufbau das passende Stylesheet. **Schritt 1: Auslöser bereitstellen** Der Nutzer wählt die Variante über einen Link. Der Klick löst einen Seitenaufruf aus, erst dabei kann der Wert gesetzt werden (siehe [Zeitpunkt der Ausführung](#grundkonzept)). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Darkmode aktivieren Darkmode ausschalten ``` **Schritt 2: Auswahl beim Seitenaufbau ins Cookie schreiben** Die Gültigkeitsdauer von 365 Tagen (in Sekunden) sorgt dafür, dass die Auswahl über die Sitzung hinaus erhalten bleibt. Ohne diesen Wert wäre es nur ein Session-Cookie und die Einstellung wäre nach dem Schließen des Browsers verloren. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsViews.current.params.theme }} {{ $wsCookie.setCookie("wsThemeColor", $wsViews.current.params.theme, 31536000) }} {{ /if }} ``` **Schritt 3: Bei jedem Seitenaufruf lesen und passendes Stylesheet laden** Das Cookie speichert lediglich die Auswahl. Die sichtbare Änderung entsteht erst durch das passende [Stylesheet](/glossar#stylesheet). Deshalb gibt es eine Weiche zwischen Dark- und Light-Variante. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $currentTheme = $wsCookie.getCookie("wsThemeColor") }} {{ if $currentTheme == "dark" }} {{ else }} {{ /if }} ``` **Ergebnis**\ Die gewählte Variante bleibt über alle Seitenaufrufe hinweg erhalten, bis der Nutzer sie wechselt. ### Onsite-Personalisierung: zielgruppenspezifische Inhalte Auslöser ist hier der Einstiegsweg, also ein Kampagnen-Link, über den der Besucher in den Shop kommt. Anders als die persönliche Begrüßung ist dies echte [Onsite-Personalisierung](/glossar#onsite-personalisierung): Sie spielen abhängig von einem Merkmal des Besuchers unterschiedliche Inhalte auf den Shop-Seiten aus. Das Szenario: Ein Tierbedarfs-Shop verschickt getrennte Newsletter an Katzen- und Hundehalter. Über den Link im Newsletter merkt sich der Shop die Zielgruppe und zeigt fortan passende Inhalte. **Schritt 1: Kampagnen-Link im Newsletter** Die Links im Newsletter tragen die Zielgruppe als Parameter: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Zu unseren Katzen-Angeboten Zu unseren Hunde-Angeboten ``` **Schritt 2: Zielgruppe beim Seitenaufbau ins Cookie schreiben** Ruft der Besucher den Shop über den Link auf, liest das Template den Parameter aus und speichert die Zielgruppe. Die Gültigkeitsdauer von 30 Tagen (2592000 Sekunden) sorgt dafür, dass die Zuordnung auch bei späteren Besuchen erhalten bleibt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsViews.current.params.kundengruppe }} {{ $wsCookie.setCookie("kundengruppe", $wsViews.current.params.kundengruppe, 2592000) }} {{ /if }} ``` **Schritt 3: Auf jeder Seite die passenden Inhalte anzeigen** Auf den Shop-Seiten ermitteln Sie die Zielgruppe und blenden die passenden Inhalte ein. Wichtig: Ein frisch gesetztes Cookie ist erst beim **nächsten** Seitenaufruf lesbar (siehe [Zeitpunkt der Ausführung](#grundkonzept)). Beim ersten Aufruf über den Kampagnen-Link greifen Sie deshalb auf den Parameter zurück und erst danach auf das Cookie. So sieht der Besucher schon beim Einstieg die richtigen Inhalte. Ist weder Parameter noch Cookie vorhanden, zeigen Sie einen neutralen Standardinhalt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $gruppe = $wsViews.current.params.kundengruppe }} {{ if not $gruppe }} {{ $gruppe = $wsCookie.getCookie("kundengruppe") }} {{ /if }} {{ if $gruppe == "katze" }}

    Unsere Bestseller für Katzen

    {{# hier die Banner und Produkte für Katzenhalter #}} {{ else }} {{ if $gruppe == "hund" }}

    Unsere Bestseller für Hunde

    {{# hier die Banner und Produkte für Hundehalter #}} {{ else }}

    Für Katzen- und Hundefreunde

    {{# neutraler Standardinhalt, solange keine Zielgruppe bekannt ist #}} {{ /if }} {{ /if }} ``` **Ergebnis**\ Besucher aus dem Katzen-Newsletter sehen bei jedem Aufruf die Katzen-Inhalte, Besucher aus dem Hunde-Newsletter die Hunde-Inhalte. Alle anderen sehen den Standardinhalt. Hinweis: Der Cookie-Wert ist im Browser lesbar und kann vom Nutzer verändert werden. Verwenden Sie die Zielgruppe daher nur zur Anzeige von Inhalten, nicht für sicherheitsrelevante Entscheidungen wie Preise oder Zugriffsrechte. Da es sich nicht um ein technisch notwendiges Cookie handelt, prüfen Sie zuvor die Einwilligung des Nutzers. ### Extern gesetztes Cookie lesen Auslöser ist hier ein Cookie, das außerhalb des Shops gesetzt wurde, beispielsweise per eigenem JavaScript oder durch ein Tool eines Drittanbieters. Solche Cookies behalten ihren ursprünglichen Namen und werden nicht automatisch umbenannt. Um sie auszulesen, übergeben Sie `keepNameAsIs: true`. Andernfalls sucht der Shop nach dem umbenannten Namen und findet das Cookie nicht. Im Beispiel hat ein per JavaScript gesetztes [Flag](/glossar#flag) vermerkt, dass ein Info-Popup bereits gesehen wurde: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{# Das Cookie wurde per JavaScript gesetzt: document.cookie = "infoPopupSeen=true" Im Template lesen wir es mit keepNameAsIs unverändert aus. #}} {{ var $popupSeen = $wsCookie.getCookie("infoPopupSeen", { keepNameAsIs: true }) }} {{ if $popupSeen != "true" }} {{# Cookie nicht vorhanden, Info-Popup anzeigen #}} {{ /if }} ``` **Ergebnis**\ Das Popup erscheint nur, solange das extern gesetzte Flag fehlt. ### Affiliate-Conversion-Tracking mit externem Cookie Auslöser ist hier ein extern gesetztes Cookie in Kombination mit dem Kaufabschluss. Affiliate-Netzwerke (z. B. Awin) setzen beim Klick auf einen Partner-Link ein eigenes Cookie mit einer Klick-Kennung. Wird die Bestellung abgeschlossen, meldet der Shop die Conversion an das Netzwerk zurück und übergibt dabei diese Klick-Kennung, damit die Vermittlung dem richtigen Partner zugeordnet wird. Zwei Dinge sind dabei für `$wsCookie` entscheidend: Das Netzwerk-Cookie wurde außerhalb des Shops gesetzt und wird deshalb mit `keepNameAsIs: true` gelesen. Und weil Conversion-Tracking dem Marketing dient, wird es erst nach der Einwilligung des Nutzers ausgeführt. Die Einwilligung prüfen Sie über [\$wsConsent](/frontend/referenz/module/wsconsent) – nicht über ein separat ausgelesenes Consent-Cookie. **Schritt 1: Klick-Kennung aus dem externen Cookie lesen** Das Cookie des Netzwerks (im Beispiel `awc`) behält seinen Original-Namen, daher `keepNameAsIs: true`. Fehlt es, bleibt der Wert leer. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $awcCookie = $wsCookie.getCookie("awc", { keepNameAsIs: true }) }} ``` **Schritt 2: Nur bei Marketing-Einwilligung tracken** Statt ein fremdes Consent-Cookie auszulesen, prüfen Sie die Einwilligung über `$wsConsent`. Nur wenn die Marketing-Einwilligung vorliegt, werden der Tracking-Aufruf und das Zählpixel ausgegeben. Die übergebenen Bestelldaten (Summe, Bestellnummer, Gutschein, Währung) stammen aus dem Checkout. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{# Marketing-Einwilligung prüfen – genaue Kategorie/Signatur siehe $wsConsent #}} {{ if $wsConsent.checkAllowed("marketing") }} {{ var $eventData = join([ "&merchant=00000", "&amount=", $wsCheckout.sum.totalNet, "&ch=aw", "&parts=DEFAULT:", $wsCheckout.sum.totalNet, "&vc=", ifnull($wsVoucher.vouchers[0].id, ""), "&cr=", $wsCheckout.sum.currency, "&ref=", $wsCheckout.orderId, "&testmode=0", "&cks=", ifnull($awcCookie, "") ], "") }} {{ $wsAsse.fire("dwintracking", $eventData) }} {{ /if }} ``` **Ergebnis**\ Liegt die Marketing-Einwilligung vor, wird die Conversion inklusive der externen Klick-Kennung an das Affiliate-Netzwerk gemeldet. Ohne Einwilligung passiert nichts. Hinweis: Der `merchant`-Wert (`00000`), das Event `dwintracking`, der Cookie-Name `awc` und die Awin-spezifischen Aufrufe sind netzwerk- bzw. shopspezifisch und hier nur beispielhaft. Der für `$wsCookie` relevante Teil ist das Lesen des externen Cookies mit `keepNameAsIs: true`; die Einwilligung wird über [\$wsConsent](/frontend/referenz/module/wsconsent) geprüft, nicht über ein eigenes Consent-Cookie. *** ## Weiterführende Links * [\$wsConsent](/frontend/referenz/module/wsconsent) – Einwilligung des Nutzers prüfen, bevor Sie nicht-notwendige Cookies setzen. # $wsOptions - Template-Optionen Source: https://dokumentation.websale.de/frontend/referenz/module/ws-options-template-optionen Werte von Template-Optionen im Frontend auslesen – global oder pro Konfigurationsknoten. Mit dem `$wsOptions`-Modul lesen Sie im Frontend die Werte von Template-Optionen aus. Template-Optionen sind Einstellungen, die einmal im Template definiert werden und danach im Admin-Interface pflegbar sind - ohne dass das Template erneut angepasst werden muss. Damit lassen sich Darstellungs-Details umschalten (z. B. ob das Icon einer Zahlungsart im Footer erscheint), ohne ins Template einzugreifen. Auf dieser Seite geht es um das Lesen der Optionswerte. Wie Optionen definiert werden (Typen, Wertgrenzen, `attachTo`, Darstellung im Admin-Interface), beschreibt [Template-Optionen definieren](/frontend/referenz/optionen). *** ## Grundkonzept Eine Template-Option durchläuft immer denselben Ablauf: definieren → im Admin pflegen → im Template lesen. * **Definieren:** Die Option wird in einem Template mit der Anweisung `{{ option … }}` angelegt (siehe [Template-Optionen definieren](/frontend/referenz/optionen)). * **Verfügbar werden:** Definierte Optionen erscheinen im Admin-Interface, nachdem die Templates erfolgreich kompiliert wurden. Wird eine Option wieder aus den Templates entfernt, verschwindet sie erst nach erneuter Kompilierung aus dem Admin-Interface. * **Pflegen:** Die Werte werden im Admin-Interface gesetzt. Bei an Konfigurationen gebundenen Optionen je Konfigurationsknoten unterschiedlich (siehe `attachTo`). * **Lesen:** im Template über `$wsOptions.get(…)`. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsOptions` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsOptions | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "get": "ƒ()" } ``` Anmerkung: `ƒ()` kennzeichnet eine Funktion. **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ----------- | ----------------------- | --------------------------------------------------------------------------- | | `get()` | abhängig vom Optionstyp | Liest den Wert einer Template-Option (global oder je Konfigurationsknoten). | *** ## Templates Template-Optionen lassen sich in jedem Template lesen. *** ## Variablen Für `$wsOptions` stehen keine Variablen zur Verfügung. Der Zugriff erfolgt ausschließlich über die Methode `get()`. *** ## Methoden ### \$wsOptions.get() Gibt den im Admin-Interface gepflegten Wert einer Template-Option zurück. Ohne zweiten Parameter wird eine globale Option gelesen. Bei Optionen, die mit `attachTo` an einen Konfigurationsknoten gebunden sind, geben Sie die Knoten-ID als zweiten Parameter an. **Signatur**\ `$wsOptions.get(name, nodeId)` **Rückgabe**\ Der gepflegte Wert der Option. Der Typ entspricht dem bei der Definition festgelegten Optionstyp (`String`, `Bool`, `Int`, `Float`, `Enum`).\ Wurde die Option im Admin-Interface noch nicht explizit gesetzt, wird `null` zurückgegeben. Prüfen Sie den Rückgabewert daher vor der Verwendung (z. B. mit `if`), damit das Template bei einer noch nicht gepflegten Option nicht ungewollt leer bleibt. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | -------- | ------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------- | | `name` | string | ja | Name der Option, wie im Template definiert. | | `nodeId` | string | nein | ID des Konfigurationsknotens. Nur bei `attachTo`-Optionen anzugeben (siehe unten). Ohne Angabe wird der globale Wert gelesen. | **Beispiel** – globale Option: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsOptions.get("intValue") }} ``` Gibt den Wert der Option `intValue` aus. **Beispiel** – an einen Konfigurationsknoten gebundene Option: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsOptions.get("attached", "payment.payment.bill") }} ``` Gibt den Wert der Option `attached` für die Zahlungsart mit dem Konfigurationsknoten `payment.payment.bill` (z. B. „Vorkasse") zurück. Der zweite Parameter ist nötig, weil dieselbe Option bei frei erstellbaren Konfigurationen, etwa einer Konfiguration je Zahlungsart, pro Knoten unterschiedlich gesetzt sein kann (z. B. bei „Vorkasse" deaktiviert, bei „Google Pay" aktiviert). #### nodeId – die ID des Konfigurationsknotens Verwechseln Sie die **Konfigurationsknoten-ID** (`nodeId`) nicht mit dem Feld `id` innerhalb einer Konfiguration. Die Konfiguration `payment.payment` enthält beispielsweise ein eigenes Feld `id` (eine „technische ID") – dieses kann **nicht** als `nodeId` verwendet werden. Damit Sie die korrekte Knoten-ID zur Hand haben, stellen die folgenden Objekte ein Feld `nodeId` bereit: * [`$wsAccount`](/frontend/referenz/module/wsAccount): `addressFields` * [`$wsAsse`](/frontend/referenz/module/wsasse): `asseConfigs` * [`$wsCategories`](/frontend/referenz/module/wscategories): `fields`, `customFields` * [`$wsConfig`](/frontend/referenz/module/wsconfig): `countries`, `payments`, `shippingMethods`, `shippingMethodGroups`, `currency`, `emails`, `listElements`, `redirects` * [`$wsForm`](/frontend/referenz/module/wsform): `loadType` / `loadAllTypes` sowie deren `fields` / `loadField` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $payment in $wsConfig.payments }} {{= $wsOptions.get("attached", $payment.nodeId) }} {{ /foreach }} ``` Hier liefert `$payment.nodeId` die Knoten-ID der jeweiligen Zahlungsart, die direkt als zweiter Parameter übergeben wird. *** ## Aktionen Für `$wsOptions` stehen keine Aktionen zur Verfügung. *** ## Beispiele ### Zahlungsarten je Zahlungsart im Footer ein- oder ausblenden In diesem Beispiel wird eine an `payment.payment` gebundene Option definiert, die im Footer nur die Zahlungsarten anzeigt, für die die Option im Admin-Interface aktiviert wurde. So können Sie pro Zahlungsart entscheiden was angezeigt wird, ohne das Template anzupassen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ option "methodLocationFooter" with { "type": "Bool", "attachTo": "payment.payment" } }} {{ foreach $method in $wsConfig.payments }} {{ if $wsOptions.get("methodLocationFooter", $method.nodeId) }}

    {{= $method.name }}

    {{ /if }} {{ /foreach }} ``` **Ergebnis**\ Im Footer werden nur die Zahlungsarten angezeigt, für die die Option "`methodLocationFooter`" aktiviert ist. Da diese Option an `payment.payment` gebunden ist, wird sie pro Zahlungsart über deren `nodeId` gelesen. Wenn die Option für eine Zahlungsart nicht gesetzt ist, gibt `get()` den Wert `null` zurück und der `if`-Zweig wird nicht ausgeführt. *** ## Weiterführende Links * [Template-Optionen definieren](/frontend/referenz/optionen) – Syntax, Typen, Wertgrenzen, `attachTo` und Darstellung im Admin-Interface. * [\$wsConfig](/frontend/referenz/module/wsconfig) – liefert u. a. `payments` inklusive `nodeId`. * [Konfiguration per Code](/frontend/die-basics/konfiguration-per-code) – Konfiguration direkt im Template. * [Storefront API Optionen](/schnittstellen/storefront-api/storefront-api-optionen) - dieselben Optionswerte über die Storefront-API auslesen. # $wsAccount - Account & Adressdaten Source: https://dokumentation.websale.de/frontend/referenz/module/wsAccount Account- und Adressdaten des eingeloggten Kunden im Frontend lesen, Login-Status prüfen und personalisierte Inhalte über Templates ausgeben. Mit dem `$wsAccount`-Modul lesen Sie die Account- und Adressdaten des aktuell eingeloggten Kunden und zeigen sie im Template an. Auf dieser Seite geht es ausschließlich um das Lesen und Anzeigen vorhandener Account- und Adressdaten. Alles, was Daten verändert (Adresse anlegen, bearbeiten, löschen, Passwort ändern), ist unter [Aktionen → Account](/frontend/referenz/aktionen/account) beschrieben, weil dort die auslösenden Aktionen und ihre Parameter dokumentiert sind. Die meisten Werte von `$wsAccount` sind nur gefüllt, wenn der Kunde eingeloggt ist. Prüfen Sie deshalb vor dem Zugriff mit `$wsAccount.isLoggedIn`, ob ein Kunde angemeldet ist, sonst lesen Sie leere Werte aus und zeigen unbeabsichtigt leere Felder an. *** ## Grundkonzept Die Arbeit mit `$wsAccount` folgt immer demselben Ablauf:
    Login-Zustand prüfen → Kundendaten lesen → reagieren. Bevor Sie Kundendaten lesen, müssen Sie wissen, ob überhaupt ein Kunde eingeloggt ist. Erst der eingeloggte Zustand füllt die Variablen mit Werten. Anschließend lesen Sie die gewünschten Daten (z. B. den Anzeigenamen oder eine Adresse) und reagieren darauf, etwa mit einer persönlichen Begrüßung oder der Anzeige des Adressbuchs. **Wann die Daten verfügbar sind**
    Wenn kein Kunde eingeloggt ist, geben die Account-Abfragen leere Werte zurück. Deshalb beginnt nahezu jedes Beispiel auf dieser Seite mit einer `isLoggedIn`-Prüfung. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsAccount` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsAccount | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "addressFields": [...], "addresses": [...], "autoLogInRestriction": "...", "backInStockList": [...], "customerData": { ... }, "defaultBillAddress": { ... }, "defaultDeliveryAddress": { ... }, "displayName": "...", "email": "...", "id": "...", "isAccountVerified": true, "isAutoLogInRestricted": true, "isAutoLoggedIn": true, "isLoggedIn": true, "isPasswordResetRequired": true, "lastLogin": "...", "loadAddress": "ƒ()", "hasPaymentVault": false, "loginRequired": "ƒ()", "pseudoCreditCards": [...], "typeSeparation": { ... } } ``` Anmerkung: `"ƒ()"` kennzeichnet eine Funktion (Methode). **Variablen in der Übersicht** | **Name** | **Rückgabe-Typ** | **Beschreibung** | | ------------------------- | ---------------- | --------------------------------------------------------------------------------- | | `addressFields` | array | Liste aller verfügbaren Adressfelder mit deren Konfiguration. | | `addresses` | array | Liste aller gespeicherten Adressen des Kunden. | | `autoLogInRestriction` | string | Status der Auto-Login-Einschränkung. | | `backInStockList` | array | Produkte, für die der Kunde eine Verfügbarkeits-Benachrichtigung angefordert hat. | | `customerData` | map | Kundenspezifische Felder (z. B. Label, Typ, Wert). | | `defaultBillAddress` | map | Haupt-Rechnungsadresse als Adress-Map. | | `defaultDeliveryAddress` | map | Standard-Lieferadresse als Adress-Map. | | `displayName` | string | Anzeigename des Kunden. | | `email` | string | E-Mail-Adresse des Kundenkontos. | | `id` | string | Nutzer-ID des Kundenkontos. | | `isAccountVerified` | bool | Prüft, ob das Kundenkonto verifiziert wurde. | | `isAutoLoggedIn` | bool | Prüft, ob der Nutzer automatisch eingeloggt wurde. | | `isAutoLogInRestricted` | bool | Prüft, ob beim automatischen Login nicht alle Shop-Funktionen verfügbar sind. | | `isLoggedIn` | bool | Prüft, ob der Nutzer eingeloggt ist. | | `isPasswordResetRequired` | bool | Prüft, ob das Passwort zurückgesetzt werden muss. | | `lastLogin` | string | Datum des letzten Logins. | | `pseudoCreditCards` | array | Gespeicherte Kreditkarten (pseudonymisiert). | | `typeSeparation` | map | Informationen zur Adresstyp-Trennung. | **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ------------------- | ---------------- | --------------------------------------------------------------------------------- | | `loadAddress()` | map | Lädt eine Adresse anhand ihrer ID. | | `hasPaymentVault()` | bool | Prüft, ob für eine Zahlungsart eine Verknüpfung mit dem Zahlungsanbieter besteht. | | `loginRequired()` | bool | Gibt zurück, ob eine bestimmte Aktion einen Login erfordert. | *** ## Templates Die Daten eines eingeloggten Kunden können auf jedem Template geladen und angezeigt werden. Im Standard-Ausliefershop befinden sich die Templates für die Seiten des Kundenkontos im Verzeichnis `views/account`. Sie dienen als Grundlage zur Anzeige und Bearbeitung der Kundendaten. Sie können diese Daten aber auch in anderen Templates nutzen. Voraussetzung ist, dass der Kunde eingeloggt ist (siehe [Grundkonzept](#grundkonzept)). *** ## Variablen ### \$wsAccount.isLoggedIn Gibt zurück, ob der Nutzer eingeloggt ist. Diese Prüfung steht am Anfang fast jeder Account-Auswertung, weil alle übrigen Variablen erst im eingeloggten Zustand sinnvolle Werte liefern. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.isLoggedIn }} {{ else }} {{ /if }} ``` ### \$wsAccount.email Gibt die E-Mail-Adresse des Kundenkontos zurück. Im Checkout kann ein Kunde auch als Gast bestellen. Dann liegt keine Konto-E-Mail vor, sondern eine Gast-Mailadresse aus dem Checkout. Das folgende Beispiel deckt deshalb beide Fälle ab, damit immer die passende Adresse angezeigt wird: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.guestMail }} {{= $wsCheckout.guestMail }} {{ else }} {{= $wsAccount.email }} {{ /if }} ``` > `$wsCheckout.guestMail` stammt aus dem Modul [\$wsCheckout](/frontend/referenz/module/wscheckout) und ist nur während des Bestellvorgangs gefüllt. ### \$wsAccount.id Gibt die Nutzer-ID des Kundenkontos zurück. Verwenden Sie sie, um einen Kunden eindeutig zu identifizieren, etwa für das Tracking. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.isLoggedIn }} Nutzer-ID: {{= $wsAccount.id }} {{ /if }} ``` ### \$wsAccount.isAccountVerified Gibt zurück, ob das Kundenkonto verifiziert wurde. Werten Sie das aus, wenn bestimmte Funktionen erst nach Verifizierung freigeschaltet werden sollen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.isAccountVerified }} {{ /if }} ``` ### \$wsAccount.isAutoLoggedIn Gibt zurück, ob der Nutzer automatisch eingeloggt wurde (über „Angemeldet bleiben"). Das ist relevant, weil ein automatischer Login eingeschränkt sein kann (siehe `isAutoLogInRestricted`). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.isAutoLoggedIn }} {{ /if }} ``` ### \$wsAccount.isAutoLogInRestricted Gibt zurück, ob beim automatischen Login nicht alle Shop-Funktionen verfügbar sind. Werten Sie das aus, bevor Sie einem automatisch eingeloggten Kunden sicherheitsrelevante Aktionen (z. B. Adressänderung) anbieten, denn diese können eine erneute Anmeldung erfordern.
    Mehr dazu [in der Konfiguration](/konfiguration/accounts-benutzerkonten#6-accounts-autologin-angemeldet-bleiben). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.isAutoLogInRestricted }} {{ /if }} ``` ### \$wsAccount.autoLogInRestriction Gibt den Status der Auto-Login-Einschränkung als Zeichenkette zurück. Mehr dazu [in der Konfiguration](/konfiguration/accounts-benutzerkonten#6-accounts-autologin-angemeldet-bleiben). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.autoLogInRestriction }} {{ /if }} ``` ### \$wsAccount.lastLogin Gibt das Datum des letzten Logins als Zeichenkette zurück. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.lastLogin }} Letzter Login: {{= $wsAccount.lastLogin }} {{ /if }} ``` ### \$wsAccount.isPasswordResetRequired Gibt zurück, ob das Passwort zurückgesetzt werden muss. Werten Sie das aus, um den Kunden gezielt zur Passwortänderung zu führen.
    Mehr dazu [in der Konfiguration](/konfiguration/accounts-benutzerkonten#2-accounts-account-benutzerkonto). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.isPasswordResetRequired }} Bitte setzen Sie Ihr Passwort zurück. {{ /if }} ``` ### \$wsAccount.customerData Gibt kundenspezifische Felder als `map` zurück (z. B. Label, Typ und Wert). Verwenden Sie diese Variable, um zusätzlich konfigurierte Kundenfelder anzuzeigen, ohne jedes Feld einzeln zu kennen.
    Mehr dazu [in der Konfiguration](/konfiguration/accounts-benutzerkonten#5-accounts-addressfield-einzelne-adressfelder-definieren). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $field in $wsAccount.customerData }} {{= $field.value }} {{ /foreach }} ``` ### \$wsAccount.addressFields Gibt eine Liste aller verfügbaren Adressfelder mit deren Konfiguration zurück. Jedes Element ist ein Objekt mit den Eigenschaften `name` (Feldname, z.B. `firstName` ), `label` (konfigurierte Beschriftung, kann leer sein) und `dataId` . Diese Liste kann benutzt werden, um Adressformulare dynamisch aus der Konfiguration aufzubauen. Jeder Eintrag enthält zusätzlich das Feld `nodeId`, die ID des Konfigurationsknotens, nutzbar als zweiter Parameter für [`$wsOptions.get(name, nodeId)`](/frontend/referenz/module/ws-options-template-optionen) (siehe [Optionen](/frontend/referenz/optionen)). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $field in $wsAccount.addressFields }} {{= $field.name }} – {{= $field.label }} {{ /foreach }} ``` ### \$wsAccount.backInStockList Gibt die Produkte zurück, für die der Kunde eine [Benachrichtigung bei Verfügbarkeit](https://dokumentation.websale.de/frontend/referenz/aktionen/inventory#backinstockactivatenotify) angefordert hat. Zeigen Sie die Liste beispielsweise im Kundenkonto an, damit der Kunde seine vorgemerkten Produkte sieht und verwalten kann. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $product in $wsAccount.backInStockList }} {{= $product }} {{ /foreach }} ``` ### \$wsAccount.pseudoCreditCards Gibt die gespeicherten Kreditkarten in [pseudonymisierter](/glossar#pseudonymisierung) Form zurück. Die Pseudonymisierung ist gewollt, denn Vollständige Kartendaten dürfen aus Sicherheits- und Datenschutzgründen nicht im Frontend angezeigt werden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $card in $wsAccount.pseudoCreditCards }} {{= $card }} {{ /foreach }} ``` ### \$wsAccount.typeSeparation Gibt Informationen zur Adresstyp-Trennung zurück. Über diese [Map](/glossar#map) können Sie prüfen, ob Rechnungs- und Lieferadressen getrennt verwaltet werden und welche Einschränkungen gelten. #### Eigenschaften von `$wsAccount.typeSeparation` | **Eigenschaft** | **Rückgabe-Typ** | **Beschreibung** | | ---------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | bool | Prüft, ob die Adresstyp-Trennung aktiv ist. | | `canCreateBillAddress` | bool | Prüft, ob noch eine neue Rechnungsadresse angelegt werden kann. | | `maxBillAddresses` | int | Maximale Anzahl erlaubter Rechnungsadressen.
    `0` = unbegrenzt
    `-1` = Trennung deaktiviert. | | `defaultBillAddressReadonly` | bool | Prüft, ob die Haupt-Rechnungsadresse schreibgeschützt ist. | | `defaultBillAddressRequired` | bool | Prüft, ob der Kunde mindestens eine Rechnungsadresse behalten muss. Ist die Adresstyp-Trennung deaktiviert, immer `false`. | | `billAddressCount` | int | Anzahl der vorhandenen Rechnungsadressen, gezählt nach explizit gesetztem Typ. Es ist dieselbe Zählung, die das Backend seinen Regeln zugrunde legt. Ist die Adresstyp-Trennung deaktiviert, immer `0`. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.typeSeparation.enabled }} {{ if $wsAccount.typeSeparation.canCreateBillAddress }} {{ else }} {{ /if }} {{ /if }} ``` ### \$wsAccount.defaultBillAddress Gibt die Haupt-Rechnungsadresse des Kunden als Adress-Map zurück (einschließlich `id`), sofern eine als Standard markiert ist. Verwenden Sie sie, wenn gezielt die Haupt-Rechnungsadresse gebraucht wird. Die verfügbaren Eigenschaften entsprechen denen von `$wsAccount.addresses`. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.defaultBillAddress }} Vorname: {{= $wsAccount.defaultBillAddress.firstName }} Nachname: {{= $wsAccount.defaultBillAddress.lastName }} {{ /if }} ``` ### \$wsAccount.defaultDeliveryAddress Gibt die Standard-Lieferadresse des Kunden als Adress-Map zurück (einschließlich `id`), sofern eine als Standard markiert ist. Verwenden Sie sie, wenn gezielt die Standard-Lieferadresse gebraucht wird. Die verfügbaren Eigenschaften entsprechen denen von `$wsAccount.addresses`. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.defaultDeliveryAddress }} Vorname: {{= $wsAccount.defaultDeliveryAddress.firstName }} Nachname: {{= $wsAccount.defaultDeliveryAddress.lastName }} {{ /if }} ``` ### \$wsAccount.addresses Gibt die Liste aller gespeicherten Adressen des Kunden zurück. Verwenden Sie sie für ein Adressbuch oder wenn Sie über alle Adressen iterieren möchten. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $address in $wsAccount.addresses }} {{= $address.firstName }} {{= $address.lastName }} {{ /foreach }} ``` Alle Adressen aus `$wsAccount.addresses` (und ebenso aus `defaultBillAddress`, `defaultDeliveryAddress` und `loadAddress()`) verfügen über die folgenden Eigenschaften. Eine Ausnahme ist die Eigenschaft`isReadonly`: Diese Eigenschaft gibt es nur an den Einträgen von `$wsAccount.addresses`, nicht an einer über `loadAddress()` geladenen Adresse. Dort liegt stattdessen die gleichnamige Feldmethode `isReadOnly()` mit abweichender Groß- und Kleinschreibung, die etwas völlig anderes tut. Prüfen Sie den Schreibschutz einer Adresse deshalb durchgängig über `isEditLocked`. #### Eigenschaften von `$wsAccount.addresses` | **Eigenschaft** | **Rückgabe-Typ** | **Beschreibung** | | -------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | Adress-ID | | `salutationCode` | string | Anredecode | | `titleCode` | string | Titelcode (z. B. Dr., Prof.) | | `firstName` | string | Vorname | | `lastName` | string | Nachname | | `company` | string | Firmenname | | `department` | string | Abteilung | | `street` | string | Straße | | `streetNumber` | string | Hausnummer | | `additionalInfo` | string | Zusätzliche Adressinformationen | | `zip` | string | Postleitzahl | | `city` | string | Stadt | | `state` | string | Bundesland / Region | | `country` | string | Land | | `phone` | string | Telefonnummer | | `mobilePhone` | string | Mobiltelefonnummer | | `fax` | string | Faxnummer | | `businessPhone` | string | Geschäftliche Telefonnummer | | `businessFax` | string | Geschäftliche Faxnummer | | `dateOfBirth` | string | Geburtsdatum | | `taxId` | string | Steuernummer | | `addressType` | string | Typ der Adresse | | `addressOwnerMemberId` | string | ID des Kunden, dem die Adresse gehört | | `custom` | map | Benutzerdefinierte Adressfelder | | `isBillAddress` | bool | Prüft, ob die Adresse als Rechnungsadresse verwendet werden kann. | | `isDeliveryAddress` | bool | Prüft, ob die Adresse als Lieferadresse verwendet werden kann. | | `isDefaultBillAddress` | bool | Prüft, ob es sich um die Haupt-Rechnungsadresse handelt. | | `isDefaultDeliveryAddress` | bool | Prüft, ob es sich um die Standard-Lieferadresse handelt. | | `isEditLocked` | bool | Prüft, ob die Adresse gegen Bearbeiten und Löschen gesperrt ist. `true` nur, wenn die Adresstyp-Trennung aktiv ist, die Haupt-Rechnungsadresse schreibgeschützt konfiguriert ist und es sich um diese Adresse handelt. | | `isReadonly` | bool | Veraltetes Synonym für `isEditLocked` und nur an den Einträgen von `$wsAccount.addresses` vorhanden. Liefert denselben Wert. Verwenden Sie in neuen Templates `isEditLocked`. | | `type` | string | Typ der Adresse (`"bill"` oder `"delivery"`). | #### \$address.customLabel() Gibt das benutzerdefinierte Label für ein bestimmtes Adressfeld zurück, abhängig vom Adresstyp. Nutzen Sie die Methode, um Formularbeschriftungen aus der Konfiguration zu übernehmen, statt sie fest im Template zu hinterlegen. **Signatur** `$address.customLabel(fieldName, addressType)` **Rückgabe** `string` – das konfigurierte Label für das Feld. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ------------- | ------- | ----------- | ------------------------------------------------------------------------------- | | `fieldName` | string | ja | Name des Adressfeldes (z. B. `"firstName"`). | | `addressType` | string | ja | Adresstyp: `"bill"` (Rechnung), `"delivery"` (Lieferung) oder `"both"` (beide). | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Vorname-Label: {{= $address.customLabel("firstName", "bill") }} ``` #### \$address.defaultValue() Gibt den konfigurierten Standardwert für ein bestimmtes Adressfeld zurück, abhängig vom Adresstyp. Nutzen Sie die Methode, um Felder mit sinnvollen Vorgaben vorzubelegen. **Signatur** `$address.defaultValue(fieldName, addressType)` **Rückgabe** `string` – der konfigurierte Standardwert für das Feld. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ------------- | ------- | ----------- | ------------------------------------------------------------------------------------- | | `fieldName` | string | ja | Name des Adressfeldes (z. B. `"company"`). | | `addressType` | string | ja | Adresstyp:
    `"bill"` (Rechnung), `"delivery"` (Lieferung) oder `"both"` (beide). | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $address.defaultValue("company", "delivery") }} ``` **Hinweis:** Die Methoden `customLabel()` und `defaultValue()` haben aktuell nur im Checkout eine Wirkung, sobald der Kunde eine Adresse ausgewählt hat. Im Kundenkonto unterscheiden sie noch nicht zwischen Liefer- und Rechnungsadresse. Das ist für eine künftige Version vorgesehen. *** ## Methoden ### \$wsAccount.loginRequired() Gibt zurück, ob der Nutzer für eine bestimmte Aktion angemeldet sein muss. Werten Sie das aus, bevor Sie eine Aktion anbieten, damit Sie einen nicht angemeldeten Kunden vorab zum Login führen, statt ihn in eine abgelehnte Aktion laufen zu lassen. Mehr dazu [in der Konfiguration](/konfiguration/accounts-benutzerkonten#6-accounts-autologin-angemeldet-bleiben). **Signatur** `$wsAccount.loginRequired(actionName)` **Rückgabe** `bool` – `true`, wenn ein Login erforderlich ist, sonst `false`. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ------------ | ------- | ----------- | --------------------------------------------------------------------------------------------- | | `actionName` | string | ja | Name der Aktion, für die geprüft wird, ob ein Login erforderlich ist (z. B. `"EmailUpdate"`). | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.loginRequired("EmailUpdate") }} {{ /if }} ``` ### \$wsAccount.loadAddress() Lädt eine einzelne Adresse anhand ihrer ID und gibt sie als Adress-Map zurück. Verwenden Sie die Methode im Checkout, um die vom Kunden gewählte Rechnungs- oder Lieferadresse auszugeben. **Signatur** `$wsAccount.loadAddress(addressId)` **Rückgabe** `map` – die geladene Adresse mit den Eigenschaften aus`$wsAccount.addresses`. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | ----------------------------------------------------------------------------- | | `addressId` | string | ja | ID der zu ladenden Adresse (z. B. die im Checkout gewählte Rechnungsadresse). | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $billAddress = $wsAccount.loadAddress($wsCheckout.selectedBillAddress) }} {{= $billAddress.firstName }} {{= $billAddress.lastName }} ``` `$wsCheckout.selectedBillAddress` stammt aus dem Modul [\$wsCheckout](/frontend/referenz/module/wscheckout) und liefert die ID der im Bestellvorgang gewählten Rechnungsadresse. ### \$wsAccount.hasPaymentVault() Prüft, ob für den angemeldeten Kunden eine Verknüpfung mit dem Zahlungsanbieter der angegebenen Zahlungsart besteht. Rufen Sie die Methode auf einer Seite im Kundenkonto auf, um entweder die bestehende Verknüpfung mit einer Möglichkeit zum Aufheben anzuzeigen oder das Angebot zur Verknüpfung einzublenden. Die Verknüpfung wird nicht der Zahlungsart selbst zugeordnet, sondern dem Zahlungsanbieter und dessen Merchant-ID. Mehrere Zahlungsarten, die denselben Zahlungsanbieter mit derselben Merchant-ID nutzen, teilen sich deshalb dieselbe Verknüpfung. **Signatur** `$wsAccount.hasPaymentVault(paymentId)` **Rückgabe** `bool` – `true` wenn eine Verknüpfung besteht, `false` wenn keine besteht. `null` wird zurückgegeben, wenn keine Prüfung möglich ist, beispielsweise wenn kein oder ein leerer `paymentID` - Wert übergeben wurde, die `paymentId` unbekannt ist oder die Zahlungsart grundsätzlich keine Verknüpfung unterstützt. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | ------------------------------------------------ | | `paymentId` | string | ja | ID der Zahlungsart, für die geprüft werden soll. | **Beispiel,** das die Verknüpfung im Kundenkonto verwaltet. Die Unterscheidung mit `== true` bzw. `== false` ist hier bewusst gewählt, damit der `null`-Fall in keinen der beiden Zweige läuft. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $hasVault = $wsAccount.hasPaymentVault("paypal") }} {{ if $hasVault == true }} {{ elseif $hasVault == false }} {{ /if }} ``` Ohne Anmeldung gibt die Methode `false` zurück, nicht `null` – prüfen Sie deshalb zuerst [`$wsAccount.isLoggedIn`](#wsaccount-isloggedin), bevor Sie aus `false` ableiten, dass der Kunde noch keine Verknüpfung angelegt hat. Innerhalb des Bestellvorgangs verwenden Sie [\$wsCheckout.hasPaymentVault()](/frontend/referenz/module/wscheckout#wscheckout-haspaymentvault) – diese Methode prüft ohne Parameter gegen die im Checkout gewählte Zahlungsart und gibt immer einen Boolean zurück. *** ## Aktionen `$wsAccount` selbst liest nur Daten. Aktionen, die Daten verändern (Adresse anlegen, bearbeiten, löschen, Passwort oder E-Mail ändern), sind separat dokumentiert: [Aktionen → Account](/frontend/referenz/aktionen/account). *** ## Beispiele Die folgenden Beispiele sind nach Anwendungsfall geordnet: von der einfachen Zustandsprüfung über die persönliche Anrede bis zur Adressauflösung im Checkout. Alle Beispiele setzen einen eingeloggten Kunden voraus und prüfen das jeweils zu Beginn. ### Login-Zustand prüfen und Inhalt unterscheiden Auslöser ist der Login-Zustand. Je nachdem, ob ein Kunde eingeloggt ist, zeigen Sie unterschiedliche Inhalte an. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.isLoggedIn }} {{ else }} {{ /if }} ``` **Ergebnis**
    Eingeloggte Kunden sehen den persönlichen Bereich, nicht angemeldete Besucher das Login-Angebot. ### Persönliche Anrede eines eingeloggten Kunden Auslöser ist der Login-Zustand. Ist ein Kunde eingeloggt, sprechen Sie ihn mit Vor- und Nachnamen aus seiner Rechnungsadresse an. Die `if`-Prüfung auf die Adresse verhindert leere Begrüßungen, falls noch keine Adresse hinterlegt ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.isLoggedIn }} {{ var $address = $wsAccount.defaultBillAddress }} {{ if $address }} Willkommen, {{= $address.firstName }} {{= $address.lastName }}! {{ /if }} {{ /if }} ``` **Ergebnis**
    Eingeloggte Kunden mit hinterlegter Rechnungsadresse werden namentlich begrüßt. ### Link zur Kundenkonto-Übersicht Auslöser ist der Login-Zustand. Für eingeloggte Kunden erzeugen Sie einen Link zur Übersichtsseite. Die URL wird über [`$wsViews.viewUrl()`](/frontend/referenz/module/wsviews) gebildet, damit der Pfad zum Template korrekt aufgelöst wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.isLoggedIn }} Zu Ihrer Kundenkonto-Übersicht {{ /if }} ``` **Ergebnis**
    Eingeloggte Kunden erhalten einen Link, der zuverlässig auf die Übersichtsseite zeigt. ### Rechnungsadresse anzeigen Auslöser ist der Login-Zustand. Sie lesen die Haupt-Rechnungsadresse aus und zeigen sie mit einem Bearbeiten-Link an. Der Link übergibt die Adress-`id`, damit die Aktion die richtige Adresse bearbeitet. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.isLoggedIn }} {{ var $address = $wsAccount.defaultBillAddress }} {{ if $address }} Ihre Rechnungsadresse {{= $address.firstName }} {{= $address.lastName }} {{= $address.street }} {{= $address.streetNumber }} {{= $address.zip }} {{= $address.city }} {{= $address.country }} Bearbeiten {{ /if }} {{ /if }} ``` **Ergebnis**
    Die Rechnungsadresse wird angezeigt und der Bearbeiten-Link führt zur richtigen Adresse. ### Adressbuch: über alle Adressen iterieren Auslöser ist der Login-Zustand. Sie iterieren über alle gespeicherten Adressen und zeigen je Adresse einen Bearbeiten-Link. Die Schleifenvariable (`$address`) wird durchgängig verwendet, damit der Link genau die Adresse der aktuellen Iteration trifft. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsAccount.isLoggedIn }} {{ foreach $address in $wsAccount.addresses }}

    Adresse-ID: {{= $address.id }}

    Bearbeiten {{ /foreach }} {{ /if }} ``` **Ergebnis**
    Jede gespeicherte Adresse wird mit einem Bearbeiten-Link aufgelistet, der auf die Übersichtsseite der Adressen weiterleitet. *** ## Weiterführende Links * [Aktionen → Account](/frontend/referenz/aktionen/account) - Adressen und Konto verändern (anlegen, bearbeiten, löschen), weil `$wsAccount` selbst nur liest. * [\$wsCheckout](/frontend/referenz/module/wscheckout) - liefert die im Bestellvorgang gewählten Adress-IDs (`selectedBillAddress`, `selectedShippingAddress`) und die Gast-Mailadresse, die in den Beispielen verwendet werden. * [Konfiguration: Accounts / Benutzerkonten](/konfiguration/accounts-benutzerkonten) - steuert Auto-Login, Verifizierung und Adressfelder, auf die mehrere Variablen verweisen. # $wsActions - Aktionen Source: https://dokumentation.websale.de/frontend/referenz/module/wsactions Frontend-Aktionen wie Login, Adresspflege oder Newsletter-Anmeldung über Links oder Formulare auslösen und Erfolgs- und Fehlerergebnisse auswerten. Mit dem `$wsActions`-Modul können Sie Aktionen im Frontend auslösen, beispielsweise ein Produkt in den Warenkorb legen, ein Formular absenden oder einen Kunden ein- bzw. ausloggen. Anschließend werten Sie das Ergebnis (Erfolg oder Fehler) aus. Auf dieser Seite geht es um das Auslösen und Auswerten von Aktionen über das `$wsActions`-Modul. Welche Aktionen es gibt und welche Parameter eine einzelne Aktion (z. B. `BasketItemAdd` oder `Login`) erwartet, ist in der [Aktionen-Referenz](/frontend/referenz/aktionen) beschrieben. Dort finden Sie die fachliche Bedeutung der einzelnen Aktionsnamen. *** ## Grundkonzept Eine Aktion durchläuft immer dieselben Schritte: Aktion vorbereiten → einbinden → auslösen → Ergebnis lesen → reagieren. Sie bereiten die Aktion im Template vor, entweder als Link mit der Funktion `url()` oder als Formularobjekt mit der Funktion `create()`. Der Kunde löst die Aktion dann durch Klicken oder Absenden aus. Der Shop führt sie aus und baut die Zielseite neu auf. Auf dieser neuen Seite finden Sie das Ergebnis unter `$wsActions.current` und können entsprechend reagieren, beispielsweise mit einer Erfolgsmeldung oder der Anzeige von Fehlern. **Wege, eine Aktion auszulösen**\ Für einen einfachen Klick, beispielsweise auf den Button „In den Warenkorb“, erzeugen Sie mit der Funktion `url()` einen Link. Wenn der Kunde etwas eingeben soll (z. B. ein Login mit Benutzername und Passwort), erzeugen Sie mit `create()` ein Aktions-Objekt und betten es in ein Formular ein. Der Unterschied liegt also darin, ob der Kunde noch Daten eingibt oder nicht. **Zeitpunkt der Ausführung:** Der Template-Code läuft beim Seitenaufbau. `$wsActions.current` enthält daher das Ergebnis der Aktion, die in der Anfrage ausgeführt wurde, mit der diese Seite erzeugt wurde. Wurde keine Aktion ausgeführt, ist `current` `null` – prüfen Sie deshalb immer zuerst auf Vorhandensein, bevor Sie auf Ergebnisse zugreifen. ### CSRF-Schutz (gilt für alle Aktionen) Jede Aktion muss ein gültiges [CSRF-Schutz-Token](/frontend/referenz/aktionen#3-2-aktionen-absichern) mitschicken, sonst lehnt der Shop die Anfrage ab. Das schützt davor, dass Aktionen von fremden Seiten heraus ungewollt ausgelöst werden. Wenn Sie Aktionen über `url()` oder `create()` erzeugen, wird das Token automatisch eingebettet. Nur wenn Sie eine Anfrage von Hand zusammenbauen, müssen Sie das Token aus [`$wsActions.csrfToken`](#wsactions-csrftoken) selbst als Parameter `wscsrf` mitgeben. ### Verfügbarkeit von `current` `$wsActions.current` ist nur gefüllt, wenn in derselben Anfrage eine Aktion ausgeführt wurde. Auf einer normal aufgerufenen Seite ist der Wert `null`. Deshalb beginnen die Ergebnisbeispiele unten mit einer Prüfung: `{{ if $wsActions.current }}`. Ohne diese Prüfung würden Sie auf null zugreifen. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsActions` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsActions | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "create": "ƒ()", "csrfToken": "...", "current": { "csrf": "...", "error": false, "errors": [ { "code": "...", "field": "...", "subCode": "...", "text": "..." } ], "errorsByField": { }, "globalErrors": [], "id": "...", "name": "...", "params": { }, "success": true, "successInfo": { }, "tag": "..." }, "url": "ƒ()" } ``` Anmerkung: `"ƒ()"` kennzeichnet eine Funktion (Methode). `current` ist `null`, wenn keine Aktion ausgeführt wurde. **Variablen und Methoden in der Übersicht** | **Name** | **Rückgabe-Typ** | **Beschreibung** | | ----------- | ---------------- | ---------------------------------------------------------------------------------------------------- | | `csrfToken` | string | CSRF-Schutz-Token der aktuellen Sitzung; als Parameter `wscsrf` mitzusenden. | | `current` | map | Ergebnis der gerade ausgeführten Aktion (Erfolg, Fehler, Meldungen). `null`, wenn keine Aktion lief. | | `create()` | map | Erzeugt ein Aktions-Objekt zur Verwendung in Formularen. | | `url()` | string | Erzeugt eine URL, die eine bestimmte Aktion ausführt (für Links). | *** ## Variablen ### \$wsActions.csrfToken Enthält das [CSRF-Schutz-Token](/frontend/referenz/aktionen#3-2-aktionen-absichern) der aktuellen Sitzung. Sie benötigen es nur, wenn Sie eine Aktionsanfrage manuell zusammenstellen. In diesem Fall muss es als Parameter „`wscsrf`“ mitgesendet werden, damit der Shop die Anfrage akzeptiert. Bei `url()` und `create()` geschieht das automatisch. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` ### \$wsActions.current Enthält das Ergebnis der im aktuellen Aufruf ausgeführten Aktion, also Erfolg oder Fehler samt Meldungen. Der Wert ist `null`, wenn keine Aktion ausgeführt wurde. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsActions.current }} {{ /if }} ``` #### Eigenschaften von `$wsActions.current` | **Eigenschaft** | **Rückgabe-Typ** | **Beschreibung** | | --------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------- | | `name` | string | Name der ausgeführten Aktion (z. B. `"BasketItemAdd"`). | | `id` | string | Eindeutige ID der Aktion. Format: `:`, falls ein Tag vergeben wurde, sonst ``. | | `csrf` | string | CSRF-Token der ausgeführten Aktion. | | `tag` | string | Vergebenes Tag der Aktion, falls vorhanden. | | `params` | map | Bereits übergebene Parameter-Werte der Aktion. | | `success` | bool | Ob die Aktion erfolgreich war. | | `successInfo` | map | Zusätzliche Informationen vom Shop bei Erfolg. | | `error` | bool | Ob ein Fehler aufgetreten ist. | | `errors` | list | Liste aller aufgetretenen Fehler (Struktur siehe unten). | | `errorsByField` | map | Fehler, einem Feld zugeordnet (Schlüssel = Feldname). | | `globalErrors` | list | Fehler, die keinem Feld zuzuordnen sind. | Das Tag (`current.tag`) wird derzeit nicht ausgewertet. Sie können es über `create()` vergeben, um mehrere gleichartige Aktionen auf einer Seite auseinanderzuhalten. #### Eigenschaften eines Fehlers (`current.errors[]`) | **Eigenschaft** | **Rückgabe-Typ** | **Beschreibung** | | --------------- | ---------------- | --------------------------------------------------------------------- | | `code` | string | Fehler-Code. | | `subCode` | string | Optionaler Code zur genaueren Spezifikation von `code`. | | `field` | string | Feld, bei dem der Fehler aufgetreten ist (leer bei globalen Fehlern). | | `text` | string | Fehlertext aus der Konfiguration. | **Name der Aktion auswerten** Prüfen Sie vor der Verarbeitung des Ergebnisses, welche Aktion ausgeführt wurde. So reagieren Sie nicht versehentlich auf eine andere Aktion. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsActions.current and $wsActions.current.name == "Login" }} {{ /if }} ``` **Erfolg auswerten** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsActions.current.success }} {{ /if }} ``` **Fehler je Feld anzeigen** `errorsByField` ordnet Fehler einem Eingabefeld zu. Nutzen Sie das, um eine Fehlermeldung direkt neben dem betroffenen Feld auszugeben, statt nur eine allgemeine Meldung. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsActions.current.errorsByField.zip }} {{ /if }} ``` **Alle Fehler auflisten** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $error in $wsActions.current.errors }} {{= $error.text }} {{ /foreach }} ``` *** ## Methoden ### \$wsActions.create() Erzeugt ein Aktions-Objekt zur Verwendung in Formularen. Verwenden Sie `create()`, wenn der Kunde vor dem Auslösen noch Daten eingibt (z. B. Login-Daten). Das Objekt liefert die Werte (u. a. `id` und `csrf`), die Sie als versteckte Formularfelder einbinden können. Das Objekt hat dieselben Eigenschaften wie `$wsActions.current`. **Signatur**\ `$wsActions.create(actionName, paramDefaults, target, tag)` **Rückgabe**\ `map` – das Aktions-Objekt. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | --------------- | ------- | ----------- | ------------------------------------------------------------------------------------------------ | | `actionName` | string | ja | Name der auszuführenden Aktion (z. B. `"BasketItemAdd"`). | | `paramDefaults` | map | nein | Vorbelegte Parameter, die beim Ausführen noch geändert werden können (z. B. eine Default-Menge). | | `target` | string | nein | Zielseite nach erfolgreicher Ausführung. | | `tag` | string | nein | Frei wählbare Bezeichnung, um mehrere Aktionen zu unterscheiden. | **Beispiel**, das eine Warenkorb-Aktion erzeugt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $action = $wsActions.create("BasketItemAdd", { productId: "12345", quantity: 1 }) }} ID: {{= $action.id }} CSRF: {{= $action.csrf }} ``` ### \$wsActions.url() Erzeugt eine URL, die eine bestimmte Aktion ausführt. Verwenden Sie `url()` für einen Link, bei dem der Kunde keine weiteren Daten eingibt (z. B. „In den Warenkorb“ oder „Abmelden“). **Signatur**\ `$wsActions.url(action, target, params)` **Rückgabe**\ `string` – die URL, die die Aktion ausführt. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | -------- | ------- | ----------- | ----------------------------------------- | | `action` | string | ja | Name der auszuführenden Aktion. | | `target` | string | ja | Zielseite nach erfolgreicher Ausführung. | | `params` | map | ja | Parameter der Aktion (z. B. `productId`). | **Beispiel**, das einen Link zum Hinzufügen in den Warenkorb erzeugt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} In den Warenkorb ``` Die Funktion `$wsViews.current.url()` stammt aus dem Modul [\$wsViews](/frontend/referenz/module/wsviews) und liefert die aktuelle Seite als Ziel. Dadurch bleibt der Kunde nach dem Hinzufügen auf derselben Seite. *** ## Beispiele ### Produkt in den Warenkorb legen und Ergebnis auswerten Dieses Beispiel zeigt den vollständigen Ablauf: Der Link löst die Aktion aus, nach dem Klick wird die Seite neu aufgebaut, und `current` wird ausgewertet. `productId` ist ein Platzhalter und muss durch die ID eines existierenden Produkts ersetzt werden. Eine nicht existierende Produkt-ID führt nicht zu einem auswertbaren `current.error`, sondern kann die Anfrage serverseitig scheitern lassen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} In den Warenkorb {{ if $wsActions.current and $wsActions.current.name == "BasketItemAdd" }} {{ if $wsActions.current.success }} Produkt wurde in den Warenkorb gelegt. {{ else }} {{ foreach $error in $wsActions.current.errors }} {{= $error.text }} {{ /foreach }} {{ /if }} {{ /if }} ``` **Ergebnis** \ Der Kunde bleibt nach dem Klick auf der Seite und sieht entweder eine Bestätigung oder die konkreten Fehlermeldungen der Aktion. ### Login-Formular mit Feldfehlern Hier gibt der Kunde Daten ein, daher wird die Aktion mit `create()` vorbereitet und in ein Formular eingebettet. Nach dem Absenden werden Fehler direkt am betroffenen Feld angezeigt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $login = $wsActions.create("Login", { }, $wsViews.current.url()) }}
    {{ if $wsActions.current.errorsByField.username }} {{= $wsActions.current.errorsByField.username }} {{ /if }}
    ``` **Ergebnis** \ Stimmen die Daten nicht, erscheint die Fehlermeldung direkt unter dem betroffenen Feld. *** ## Weiterführende Links * [Aktionen (Konzept und Referenz)](/frontend/referenz/aktionen) – was Aktionen sind, wie sie abgesichert werden und welche Aktionsnamen mit welchen Parametern es gibt. Diese Seite zeigt nur den Zugriff über `$wsActions`. * [\$wsViews](/frontend/referenz/module/wsviews) – liefert mit `current.url()` und `viewUrl()` die Zielseiten, die `url()` und `create()` als `target` erwarten. # $wsAsse - Asynchrone HTTP-Events (ASSE) Source: https://dokumentation.websale.de/frontend/referenz/module/wsasse Vorkonfigurierte Server-Side-Events auslösen, die im Hintergrund HTTP-Requests an externe URLs senden – z.B. Tracking, Webhooks oder Drittsysteme. Mit dem `$wsAsse`-Modul lösen Sie aus einem Template heraus [**ASSE-Events**](/glossar#asse) (Asynchronous Server-Side Events) aus. Ein Event sendet im Hintergrund einen HTTP-Request an eine in der Konfiguration hinterlegte externe URL um Daten an einen externen Dienst zu übermitteln (z. B. Tracking nach einer Bestellung). Auf dieser Seite geht es um das Auslösen vorkonfigurierter Events aus dem Template. Wie ein Event eingerichtet wird (Ziel-URL, HTTP-Methode, Wiederholungen, Erfolgsbedingungen), ist in der [ASSE-Konfiguration](/konfiguration/general-allgemeine-shopeinstellungen#4-general-asse-schnittstelle-für-asynchronous-server-side-events-asse) beschrieben. *** ## Voraussetzung Bevor `$wsAsse` im Template etwas bewirkt, muss mindestens ein Event in der Konfiguration angelegt sein. Ohne ein konfiguriertes Event gibt es keine Event-ID, die Sie auslösen könnten, und [`fire()`](#wsasse-fire) liefert `false`. Die [Konfiguration](/konfiguration/general-allgemeine-shopeinstellungen#4-general-asse-schnittstelle-für-asynchronous-server-side-events-asse) legt fest, welche URL aufgerufen wird, welche HTTP-Methode verwendet wird, wie oft bei Fehlern wiederholt wird und unter welchen Bedingungen ein Request als erfolgreich gilt. *** ## Grundkonzept Ein ASSE-Event durchläuft immer denselben Ablauf: Event konfigurieren → im Template auslösen → Request läuft asynchron im Hintergrund. Sie richten ein Event einmalig in der Konfiguration ein und vergeben ihm eine ID. Im Template lösen Sie es dann über [`fire()`](#wsasse-fire) unter dieser ID aus und geben optional Daten mit. Der Shop verschickt den HTTP-Request daraufhin selbstständig im Hintergrund. ### Asynchron: Rückgabe ist nicht gleich Erfolg `fire()` gibt true zurück, sobald das Event gültig konfiguriert wurde und der Request eingereiht wurde. Dies bedeutet jedoch nicht, dass der externe Server den Request erfolgreich verarbeitet hat. Da ASSE die Requests asynchron versendet, erfolgt die tatsächliche Ausführung zeitversetzt. Verlassen Sie sich deshalb nicht auf den Rückgabewert, um den Erfolg der externen Verarbeitung zu prüfen. ### Auslösung beim Seitenaufbau `fire()` wird ausgeführt, wenn das Template gerendert wird, also bei jedem Aufruf der entsprechenden Seite. Platzieren Sie den Aufruf daher nur auf der entsprechenden Seite (z. B. die Bestellbestätigung) und bedenken Sie: Wenn der Kunde die Seite neu lädt, wird das Event erneut ausgelöst. Stellen Sie bei zählrelevanten Events (z. B. Tracking) sicher, dass ein erneutes Auslösen keine Probleme verursacht. ### Daten übergeben Den optionalen zweiten Parameter `data` hängt ASSE je nach HTTP-Methode an die URL an oder sendet ihn im Request-Body. Zwei Punkte sind dabei wichtig, damit die Daten korrekt ankommen: * Der Wert wird nicht automatisch URL-kodiert. Enthält er Sonderzeichen, kodieren Sie ihn selbst. * Übergeben Sie eine Liste oder ein Objekt, wird der Wert automatisch in ein JSON-Objekt umgewandelt. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsAsse` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsAsse | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "asseConfigs": [...], "fire": "ƒ()" } ``` Anmerkung: `"ƒ()"` kennzeichnet eine Funktion (Methode). **Variablen und Methoden in der Übersicht** | **Name** | **Rückgabe-Typ** | **Beschreibung** | | ------------- | ---------------- | ---------------------------------------------------------- | | `asseConfigs` | array | Liste aller konfigurierten Events mit ihren Einstellungen. | | `fire()` | bool | Löst ein vorkonfiguriertes Event aus. | *** ## Variablen ### \$wsAsse.asseConfigs Gibt eine Liste aller konfigurierten Events mit ihren Einstellungen zurück. Nutzen Sie sie, um zu prüfen, welche Events (und damit welche Event-IDs) verfügbar sind, bevor Sie eines auslösen. Ist die Liste leer (`[]`), ist kein Event konfiguriert. Die Events werden in der [Konfiguration](/konfiguration/general-allgemeine-shopeinstellungen#4-general-asse-schnittstelle-für-asynchronous-server-side-events-asse) angelegt. Jeder Eintrag enthält zusätzlich das Feld `nodeId`, die ID des Konfigurationsknotens, nutzbar als zweiter Parameter für [`$wsOptions.get(name, nodeId)`](/frontend/referenz/module/ws-options-template-optionen) (siehe [Optionen](/frontend/referenz/optionen)). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsAsse.asseConfigs | json }} ``` *** ## Methoden ### \$wsAsse.fire() Löst ein vorkonfiguriertes Event aus. Dabei wird im Hintergrund ein HTTP-Request an die in der Konfiguration hinterlegte URL gesendet. Über den zweiten Parameter können Sie optional Daten für den aktuellen Vorgang übergeben. Je nach HTTP-Methode werden diese an die URL angehängt oder im Request-Body gesendet. **Signatur**\ `$wsAsse.fire(eventId, data)` **Rückgabe**\ `bool` - `true`, wenn das Event gültig konfiguriert ist und ausgelöst wurde, `false` bei einem Konfigurationsproblem, etwa wenn die `eventId` keinem konfigurierten Event entspricht. Beachten Sie das [asynchrone Verhalten](#asynchron-rückgabe-ist-nicht-gleich-erfolg): `true` sagt nichts über den Erfolg des externen Requests aus. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | --------- | ------- | ----------- | --------------------------------------------------------------------------------------------------- | | `eventId` | string | ja | ID des auszulösenden Events. Muss einer gültigen ID aus der Konfiguration entsprechen. | | `data` | string | nein | Zusätzliche Daten, die mit dem Request gesendet werden (siehe [Daten übergeben](#daten-übergeben)). | **Beispiel**, das ein vorkonfiguriertes Event `myevent` mit der Nutzer-ID auslöst: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $eventData = "userid=" + $wsAccount.id }} {{ $wsAsse.fire('myevent', $eventData) }} ``` \$wsAccount.id stammt aus dem Modul [\$wsAccount](/frontend/referenz/module/wsAccount) und liefert die ID des eingeloggten Kunden. *** ## Beispiele ### Awin-Tracking auf der Bestellbestätigungsseite auslösen Ein häufiger Anwendungsfall ist das Senden von Tracking-Daten an einen externen Dienstleister nach einer erfolgreichen Bestellung. Dieses Beispiel baut die Bestelldaten (Bestellnummer, Warenwert, Währung) aus [\$wsCheckout](/frontend/referenz/module/wscheckout) zu einer Parameter-Zeichenkette zusammen und löst damit das Event `awintracking` aus. Da dieser Aufruf bei jedem Seitenaufbau feuert (siehe [Auslösung beim Seitenaufbau](#auslösung-beim-seitenaufbau)), gehört er ausschließlich auf die Bestellbestätigungsseite. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $eventData = "&merchant=12345" }} {{ var $eventData = $eventData + "&amount=" + $wsCheckout.sum.totalNet }} {{ var $eventData = $eventData + "&ch=aw" }} {{ var $eventData = $eventData + "&parts=DEFAULT:" + $wsCheckout.sum.totalNet }} {{ var $eventData = $eventData + "&cr=" + $wsCheckout.sum.currency }} {{ var $eventData = $eventData + "&ref=" + $wsCheckout.orderId }} {{ var $eventData = $eventData + "&testmode=0" }} {{ if $wsVoucher.vouchers[0] }} {{ var $eventData = $eventData + "&vc=" + $wsVoucher.vouchers[0].id }} {{ /if }} {{ $wsAsse.fire('awintracking', $eventData) }} ``` In der Konfiguration muss dafür ein Event mit der ID `awintracking` angelegt sein, das auf die Awin-Tracking-URL verweist. `merchant=12345` ist ein Platzhalter und durch Ihre Awin-Merchant-ID zu ersetzen. **Ergebnis** Nach Aufbau der Bestellbestätigungsseite wird der Tracking-Request im Hintergrund an Awin gesendet. *** ## Weiterführende Links * [ASSE-Konfiguration](/konfiguration/general-allgemeine-shopeinstellungen#4-general-asse-schnittstelle-für-asynchronous-server-side-events-asse) – legt Ziel-URL, HTTP-Methode, Wiederholungen und Erfolgsbedingungen eines Events fest. Voraussetzung, damit `fire()` etwas bewirkt. * [\$wsCheckout](/frontend/referenz/module/wscheckout) – liefert die Bestelldaten, die im Tracking-Beispiel übergeben werden. * [\$wsAccount](/frontend/referenz/module/wsAccount) – liefert die im einfachen Beispiel verwendete Nutzer-ID. # $wsBasket - Warenkorb Source: https://dokumentation.websale.de/frontend/referenz/module/wsbasket Warenkorbdaten im Frontend lesen: Positionen, Mengen, Beträge, Rabatte, Steuerinformationen und Werbemittelkennzeichen für Mini-Cart, Übersicht und Checkout. Mit dem `$wsBasket`-Modul lesen Sie die Daten des aktuellen Warenkorbs im Frontend. Die enthaltenen Produkte (Positionen), deren Mengen und Preise sowie die berechneten Gesamtwerte und Steuerinformationen. Auf dieser Seite geht es um das Lesen der Warenkorb-Daten. Alles, was den Warenkorb verändert (Produkt hinzufügen, Menge ändern, entfernen), ist unter [Aktionen → Basket](/frontend/referenz/aktionen/basket) beschrieben, weil dort die auslösenden Aktionen und ihre Parameter dokumentiert sind. *** ## Grundkonzept Der Warenkorb speichert die vom Kunden ausgewählten Produkte und berechnet automatisch die Mengen, Preise und Steuern. Über dieses Modul können Sie diese Werte auslesen und anzeigen. ### Aufbau Die Warenkorb-Daten sind in drei Ebenen verschachtelt: * **Warenkorb** (`$wsBasket`) - die Gesamtwerte über alle Positionen hinweg, z. B. `total` oder [`totalQuantity`](#wsbasket-totalquantity). * **Positionen** (`$wsBasket.items`) - eine Liste der Warenkorb-Einträge. Jeder Eintrag steht für ein Produkt im Warenkorb und hat eigene Werte wie Menge und Positionssumme. * **Produkt** (`item.product`) - innerhalb jeder Position befindet sich auch das zugehörige Produkt mit seinen Stammdaten (Name, Bild, ID). Sie lesen also Summen vom Warenkorb, positionsbezogene Werte von der jeweiligen Position und Produktdetails vom Produkt der Position. ### Steuerbefreiung Mehrere Variablen bilden zusammen die Steuerbefreiung ab und gehören inhaltlich zusammen: [`isTaxExempt`](#wsbasket-istaxexempt) ist der primäre Schalter, [`totalTaxDeduction`](#wsbasket-totaltaxdeduction) und [`totalPreDeduction`](#wsbasket-totalprededuction) liefern die Beträge für eine „abzgl. MwSt."-Zeile, und [`usedExemptionRule`](#wsbasket-usedexemptionrule) zusammen mit [`billingCountry`](#wsbasket-billingcountry)/[`shippingCountry`](#wsbasket-shippingcountry) zeigt, welche Adressen für die Prüfung herangezogen werden. Prüfen Sie für Steuerhinweise immer zuerst `isTaxExempt`. ### Werbemittelkennzeichen Ist die [Werbemittelkennzeichnung](/frontend/funktionsubersicht/werbemittelkennzeichnung) im Shop aktiviert, trägt jede Position zusätzlich das erfasste Werbemittelkennzeichen. Dafür gibt es zwei Felder: [`insert`](#wsbasket-items) liefert den reinen Code, [`itemNumberWithInsert`](#wsbasket-items) die fertig zusammengesetzte Anzeige aus Produktnummer und Code in der konfigurierten Reihenfolge und mit dem konfigurierten Trennzeichen. Ist kein Code gesetzt, enthält `itemNumberWithInsert` einfach die reine Produktnummer. In der Regel reicht es, `itemNumberWithInsert` als Artikelnummer auszugeben - Position und Trennzeichen sind darin bereits berücksichtigt. Zusätzliche Ausgaben rund um das Werbemittelkennzeichen (beispielsweise ein separates Code-Label) gehören in `{{ if $wsConfig.inserts.enabled }} … {{ /if }}`, damit bei ausgeschalteter Funktion nichts erscheint. Die Einstellungen liefert [\$wsConfig.inserts](/frontend/referenz/module/wsconfig#wsconfig-inserts). ### Zeitpunkt und zuletzt geänderter Artikel Der Template-Code läuft beim Seitenaufbau. `$wsBasket` enthält daher den Warenkorb-Zustand nach der zuletzt ausgeführten Aktion. [`lastBasketAction`](#wsbasket-lastbasketaction) und `lastUpdatedItem` beschreiben diese letzte Änderung. Nützlich, um beispielsweise direkt nach dem Hinzufügen eine Rückmeldung wie „Produkt X wurde hinzugefügt" anzuzeigen. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsBasket` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsBasket | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "billingCountry": "...", "isTaxExempt": true, "items": [ { "discountPrice": 0.0, "freeFields": { }, "id": "...", "insert": "...", "itemNumberWithInsert": "...", "oneTimeFee": 0.0, "orgPrice": 0.0, "price": 0.0, "product": { }, "quantity": 0.0, "total": 0.0, "totalGross": 0.0, "totalNet": 0.0, "totalTax": 0.0, "voucherIds": [...] } ], "lastBasketAction": "...", "lastUpdatedItem": { "categories": [...], "freeFields": { }, "id": "...", "parentCategories": [...], "price": 0.0, "productNumber": "...", "quantity": 0.0, "taxId": "...", "voucherIds": [...] }, "shippingCountry": "...", "total": 0.0, "totalCommission": 0.0, "totalGross": 0.0, "totalNet": 0.0, "totalQuantity": 0.0, "totalTax": 0.0, "totalTaxDeduction": 0.0, "totalPreDeduction": 0.0, "totalWeight": 0.0, "usedExemptionRule": "..." } ``` **Variablen des Warenkorbs (oberste Ebene)** | **Variable** | **Rückgabe-Typ** | **Beschreibung** | | ------------------- | ---------------- | ---------------------------------------------------------------------- | | `totalQuantity` | float | Gesamtmenge aller Produkte im Warenkorb. | | `total` | float | Gesamtbetrag des Warenkorbs. | | `totalNet` | float | Nettobetrag des Warenkorbs. | | `totalGross` | float | Bruttobetrag des Warenkorbs. | | `totalTax` | float | Mehrwertsteuer des Warenkorbs. | | `totalCommission` | float | Gesamt-Provision. | | `totalWeight` | float | Gesamtgewicht aller Produkte im Warenkorb. | | `lastBasketAction` | string | Letzte Aktion am Warenkorb (z. B. `"add"`, `"remove"`, `"update"`). | | `lastUpdatedItem` | map | Zuletzt geänderter Artikel (Struktur siehe unten). | | `items` | array | Liste aller Warenkorb-Einträge (Struktur siehe unten). | | `isTaxExempt` | bool | Ob der aktuelle Warenkorb steuerbefreit ist. | | `totalTaxDeduction` | float | Betrag der abgezogenen Steuer; nur > 0 bei aktiver Steuerbefreiung. | | `totalPreDeduction` | float | Gesamtbetrag vor dem Steuerabzug. | | `billingCountry` | string | Länderkennung der Rechnungsadresse (z. B. `"DE"`). | | `shippingCountry` | string | Länderkennung der Lieferadresse (z. B. `"DE"`). | | `usedExemptionRule` | string | Aktive Steuerprüfregel (`"shippingOnly"` oder `"shippingAndBilling"`). | *** ## Templates Die Warenkorb-Daten lassen sich auf jeder Seite des Shops anzeigen. Übliche Darstellungen sind: * **Offcanvas-Warenkorb:** in einer Sidebar, als Flyout oder als OffCanvas-Element, für einen schnellen Überblick. * **Warenkorb-Seite:** eine detaillierte Übersicht mit Anpassungsmöglichkeiten. * **Checkout und Bestellbestätigung:** Darstellung während des Kaufprozesses und in Bestätigungs-E-Mails. *** ## Variablen ### \$wsBasket.totalQuantity Gibt die Gesamtmenge aller Produkte im Warenkorb aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Artikel im Warenkorb: {{= $wsBasket.totalQuantity }} ``` ### \$wsBasket.total Gibt den Gesamtbetrag des Warenkorbs aus. Verwenden Sie ihn für die Endsumme in Warenkorb und Checkout. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Gesamtbetrag: {{= $wsBasket.total | currency }} ``` ### \$wsBasket.totalNet Gibt den Nettobetrag des Warenkorbs aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Nettobetrag: {{= $wsBasket.totalNet | currency }} ``` ### \$wsBasket.totalGross Gibt den Bruttobetrag des Warenkorbs aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Bruttobetrag: {{= $wsBasket.totalGross | currency }} ``` ### \$wsBasket.totalTax Gibt die Mehrwertsteuer des Warenkorbs aus. Nutzen Sie sie für eine separate Steuerzeile in der Summenübersicht. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Mehrwertsteuer: {{= $wsBasket.totalTax | currency }} ``` ### \$wsBasket.totalCommission Gibt die Gesamt-Provision des Warenkorbs aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Provision: {{= $wsBasket.totalCommission | currency }} ``` ### \$wsBasket.totalWeight Gibt das Gesamtgewicht aller Produkte im Warenkorb aus. Nützlich, um z. B. einen Versandkosten- oder Gewichtshinweis anzuzeigen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Gesamtgewicht: {{= $wsBasket.totalWeight }} ``` ### \$wsBasket.lastBasketAction Gibt die zuletzt am Warenkorb durchgeführte Aktion aus (z. B. `"add"`, `"remove"`, `"update"`). Werten Sie sie aus, um nach einer Änderung eine passende Rückmeldung anzuzeigen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Letzte Aktion: {{= $wsBasket.lastBasketAction }} ``` ### \$wsBasket.lastUpdatedItem Gibt den zuletzt hinzugefügten oder geänderten Artikel aus. Verwenden Sie ihn zusammen mit `lastBasketAction`, um z. B. direkt nach dem Hinzufügen „Produkt X wurde hinzugefügt" anzuzeigen, ohne den ganzen Warenkorb durchsuchen zu müssen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Zuletzt geändert: {{= $wsBasket.lastUpdatedItem.id }} Menge: {{= int($wsBasket.lastUpdatedItem.quantity) }} ``` #### Eigenschaften von `$wsBasket.lastUpdatedItem` | **Eigenschaft** | **Rückgabe-Typ** | **Beschreibung** | | ------------------ | ---------------- | -------------------------------------------------- | | `id` | string | Produkt-ID des Artikels. | | `productNumber` | string | Artikelnummer des Artikels. | | `price` | float | Preis des Artikels. | | `quantity` | float | Menge des Artikels. | | `taxId` | string | Steuersatz-ID des Artikels. | | `categories` | array | Kategorie-IDs, in denen sich der Artikel befindet. | | `parentCategories` | array | Übergeordnete Kategorie-IDs des Artikels. | | `freeFields` | map | Freie Felder des Artikels. | | `voucherIds` | array | Angewendete Gutschein-IDs für den Artikel. | ### \$wsBasket.items Gibt die Liste aller Warenkorb-Einträge (Positionen) aus. Über diese Liste iterieren Sie, um jede Position einzeln anzuzeigen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $item in $wsBasket.items }} Artikel: {{= $item.product.name }} – Menge: {{= int($item.quantity) }} {{ /foreach }} ``` #### Eigenschaften eines Eintrags in `$wsBasket.items` | **Eigenschaft** | **Rückgabe-Typ** | **Beschreibung** | | ---------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | Warenkorb-ID des Eintrags. | | `product` | map | Das zugehörige Produkt des Eintrags (Stammdaten wie Name, Bild, ID). | | `insert` | string | Das [Werbemittelkennzeichen](/frontend/funktionsubersicht/werbemittelkennzeichnung) des Eintrags. Leer, wenn kein Code gesetzt ist. | | `itemNumberWithInsert` | string | Fertig zusammengesetzte Anzeige aus Produktnummer und Werbemittelkennzeichen in der konfigurierten Reihenfolge mit Trennzeichen. Ist kein Code gesetzt, enthält das Feld die reine Produktnummer. | | `quantity` | float | Menge des Eintrags. | | `price` | float | Einzelpreis des Eintrags. | | `orgPrice` | float | Ursprünglicher Preis vor Rabatten. | | `discountPrice` | float | Rabattierter Preis (falls ein Rabatt aktiv ist). | | `oneTimeFee` | float | Einmalige Gebühr (z. B. Einrichtungskosten). | | `total` | float | Gesamtbetrag des Eintrags (Positionssumme). | | `totalNet` | float | Nettobetrag des Eintrags. | | `totalGross` | float | Bruttobetrag des Eintrags. | | `totalTax` | float | Mehrwertsteuer des Eintrags. | | `freeFields` | map | Freie Felder (z. B. Beschriftungen, Kommentare). | | `voucherIds` | array | Angewendete Gutschein-IDs für diesen Eintrag. | ### \$wsBasket.isTaxExempt Gibt aus, ob der aktuelle Warenkorb steuerbefreit ist. Dies ist der primäre Indikator für eine Steuerbefreiung – nutzen Sie ihn, um z. B. einen Hinweis „Steuerbefreite Lieferung" einzublenden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsBasket.isTaxExempt }} Dieser Warenkorb ist steuerbefreit. {{ /if }} ``` ### \$wsBasket.totalTaxDeduction Gibt den Betrag der abgezogenen Steuer aus. Der Wert ist nur größer als 0, wenn eine Steuerbefreiung aktiv ist. In Brutto-Shops stellen Sie damit z. B. eine Zeile „abzgl. MwSt." dar. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsBasket.totalTaxDeduction > 0 }} Steuerabzug: {{= $wsBasket.totalTaxDeduction | currency }} {{ /if }} ``` ### \$wsBasket.totalPreDeduction Gibt den Gesamtbetrag vor dem Steuerabzug aus. Zusammen mit `totalTaxDeduction` zeigen Sie so den Betrag vor und nach dem Abzug. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Betrag vor Steuerabzug: {{= $wsBasket.totalPreDeduction | currency }} ``` ### \$wsBasket.billingCountry Gibt die Länderkennung der Rechnungsadresse aus (z. B. `"DE"` für Deutschland). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Rechnungsland: {{= $wsBasket.billingCountry }} ``` ### \$wsBasket.shippingCountry Gibt die Länderkennung der Lieferadresse aus (z. B. `"DE"` für Deutschland). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Lieferland: {{= $wsBasket.shippingCountry }} ``` ### \$wsBasket.usedExemptionRule Gibt die aktive Steuerprüfregel aus. Mögliche Werte: `"shippingOnly"` (nur die Lieferadresse wird geprüft) oder `"shippingAndBilling"` (Liefer- und Rechnungsadresse werden geprüft). So erkennen Sie, welche Adressen über die Steuerbefreiung entscheiden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsBasket.usedExemptionRule }} Aktive Prüfregel: {{= $wsBasket.usedExemptionRule }} {{ /if }} ``` *** ## Methoden Für `$wsBasket` stehen keine Methoden zur Verfügung. *** ## Aktionen Aktionen, die den Warenkorb verändern (Produkt hinzufügen, Menge ändern, entfernen), sind separat dokumentiert: [Aktionen → Basket](/frontend/referenz/aktionen/basket). *** ## Beispiele für den Datenzugriff ### Prüfen, ob Produkte im Warenkorb liegen Prüfen Sie zuerst, ob überhaupt Positionen vorhanden sind, bevor Sie den Warenkorb anzeigen, sonst zeigen Sie eine leere Liste. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsBasket.items }}

    Im Warenkorb befinden sich {{= $wsBasket.items | len }} Positionen.

    {{ else }}

    Sie haben noch keine Produkte im Warenkorb.

    {{ /if }} ``` **Ergebnis**
    Bei gefülltem Warenkorb erscheint die Anzahl der Positionen, sonst ein Hinweis auf den leeren Warenkorb. ### Produkte im Warenkorb anzeigen Sind Positionen vorhanden, iterieren Sie über `items` und zeigen je Position Produktname, Menge und Preise. Die Gesamtsummen stehen außerhalb der Schleife weil sie sonst für jede Position erneut ausgegeben werden würden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsBasket.items }} {{ foreach $item in $wsBasket.items }} {{= $item.product.name }}

    Produktname: {{= $item.product.name }}

    Art.-Nr.: {{= $item.itemNumberWithInsert }}

    Menge: {{= int($item.quantity) }}

    Einzelpreis: {{= $item.price | currency }}

    Positionssumme: {{= $item.total | currency }}

    {{ /foreach }}

    Versandkosten: {{= $wsCheckout.sum.shippingCost | currency }}

    Gesamtsumme: {{= $wsBasket.total | currency }}

    {{ else }}

    Sie haben keine Produkte im Warenkorb!

    {{ /if }} ``` **Ergebnis**
    Jede Position wird mit Bild, Name, Artikelnummer (inklusive Werbemittelkennzeichen, sofern erfasst), Menge und Preisen aufgelistet. Darunter erscheinen Versandkosten und Gesamtsumme einmalig. ### Werbemittelkennzeichen separat ausgeben Soll der reine Code zusätzlich zur Artikelnummer als eigenes Feld erscheinen, prüfen Sie zuerst über [`$wsConfig.inserts.enabled`](/frontend/referenz/module/wsconfig#wsconfig-inserts), ob die Funktion aktiv ist, damit bei ausgeschalteter Funktion nichts erscheint. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsConfig.inserts.enabled }} {{ foreach $item in $wsBasket.items }} {{ if $item.insert }}

    Werbemittelcode: {{= $item.insert }}

    {{ /if }} {{ /foreach }} {{ /if }} ``` **Ergebnis**
    Der Werbemittelcode erscheint nur bei aktiver Funktion und nur für Positionen, die einen Code tragen. ### Link zur Warenkorbseite Erzeugt einen Link auf die Warenkorbseite, die über das View-Template `basket.htm` umgesetzt ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Warenkorb ansehen ``` **Ergebnis**
    Der Link führt zur Warenkorbseite des Shops. *** ## Weiterführende Links * [Werbemittelkennzeichen](/frontend/funktionsubersicht/werbemittelkennzeichnung) – fachliche Übersicht der Werbemittelkennzeichnung: Erfassungswege, Auflösungslogik und Einrichtung. * [Aktionen → Basket](/frontend/referenz/aktionen/basket) – den Warenkorb verändern (hinzufügen, ändern, entfernen), weil `$wsBasket` selbst nur liest. * [\$wsCheckout](/frontend/referenz/module/wscheckout) – liefert ergänzende Werte wie die Versandkosten (`sum.shippingCost`) für die Summenanzeige. * [\$wsViews](/frontend/referenz/module/wsviews) – erzeugt die in den Beispielen genutzten Produkt- und View-URLs. * [Praxisbeispiele Warenkorb](/frontend/praxisbeispiele/warenkorb-funktionen) – durchgängige Praxisbeispiele für Warenkorb-Funktionen. # $wsCategories - Kategorien Source: https://dokumentation.websale.de/frontend/referenz/module/wscategories Kategoriedaten im Frontend laden und anzeigen: Eigenschaften, Unterkategorien, Pfade und Produkte für Navigation, Listen und Kategorieseiten. Mit dem `$wsCategories`-Modul laden Sie Kategoriedaten und zeigen sie im Frontend an - einzelne Kategorien, ihre Unterkategorien, den Kategoriepfad (Breadcrumb) und die enthaltenen Produkte. Auf dieser Seite geht es um das Laden und Anzeigen von Kategoriedaten. Produktdetails sind in der Produkt-Referenz beschrieben; die Einrichtung der Kategorie-Navigation erfolgt im Admin-Interface (siehe [Template](#template)). *** ## Grundkonzept `$wsCategories` ist ein Lade-Modul: Es stellt nur Methoden zum Laden von Kategorien bereit und hat selbst keine „aktuelle Kategorie". Ein Aufruf wie `$wsCategories.id` existiert daher nicht. Sie arbeiten stattdessen immer mit einer Category-Map, also einem Objekt mit den [Eigenschaften einer Kategorie](#eigenschaften-einer-kategorie). Diese Map erhalten Sie auf zwei Wegen: * **Aus dem aktuellen Seitenkontext** - auf einer Kategorieseite liegt die aktuelle Kategorie unter `$wsViews.current.info.category`: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $category = $wsViews.current.info.category }} ``` * **Aus einer Lade-Methode** - z. B. eine bestimmte Kategorie über ihre ID oder die Unterkategorien einer Kategorie: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $category = $wsCategories.loadCategory("100-12345") }} ``` In beiden Fällen weisen Sie die Map einer Variablen zu und greifen anschließend auf deren Eigenschaften zu (z. B. `$category.name`). Der Variablenname ist frei wählbar, auf dieser Seite heißt er durchgängig `$category`. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsCategories` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsCategories | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "loadCategory": "ƒ()", "loadCategoryMembershipPaths": "ƒ()", "loadCategoryMemberships": "ƒ()", "loadChildren": "ƒ()", "loadPath": "ƒ()", "loadProducts": "ƒ()" } ``` Anmerkung: `"ƒ()"` kennzeichnet eine Funktion. **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ------------------------------- | ---------------- | ------------------------------------------------------------------------- | | `loadCategory()` | map | Lädt eine einzelne Kategorie anhand ihrer ID. | | `loadChildren()` | array | Lädt die direkten Unterkategorien einer Kategorie. | | `loadPath()` | array | Lädt den Kategoriepfad (Breadcrumb) von der Wurzel bis zur Kategorie. | | `loadProducts()` | array | Lädt die Produkte einer Kategorie. | | `loadCategoryMemberships()` | array | Lädt alle Kategorien, in denen ein Produkt enthalten ist. | | `loadCategoryMembershipPaths()` | array | Lädt die vollständigen Kategoriepfade für alle Kategorien eines Produkts. | Die Eigenschaften, die jede geladene Kategorie bereitstellt, sind unter [Eigenschaften einer Kategorie](#eigenschaften-einer-kategorie) beschrieben. *** ## Template Im Standard erfolgt die Anzeige von Kategorien über das Template `category.htm` (im Verzeichnisbaum unter `templates/views/category.htm`). Kategoriedaten lassen sich aber auch flexibel anderswo nutzen, beispielsweise in Blogbeiträgen oder im Warenkorb. Dafür muss das jeweilige Template bereits im Verzeichnis `views` angelegt worden sein. *** ## Eigenschaften einer Kategorie Die folgenden Eigenschaften stehen in jeder Category-Map zur Verfügung, unabhängig davon, ob Sie sie aus dem Seitenkontext oder mithilfe einer Lade-Methode erhalten haben. | **Eigenschaft** | **Rückgabe-Typ** | **Beschreibung** | | ----------------------- | ---------------- | ------------------------------------------------------------------------------------------------------- | | `id` | string | Eindeutige, vom Shop vergebene ID der Kategorie. | | `name` | string | Name der Kategorie. | | `descr` | string | Beschreibung der Kategorie. | | `active` | string | Sichtbarkeitsstatus: `"always"` (immer sichtbar), `"test"` (nur Testmodus), `"never"` (nicht sichtbar). | | `hidden` | bool | Ob die Kategorie versteckt ist (z. B. nicht in der Navigation angezeigt wird). | | `productsCount` | int | Anzahl der Produkte in der Kategorie. | | `custom` | map | Benutzerdefinierte (freie) Felder der Kategorie, z. B. Bilder oder SEO-Texte. | | `timestampCreatedAt` | datetime | Erstellungszeitpunkt der Kategorie. | | `timestampUpdatedAt` | datetime | Zeitpunkt der letzten Änderung. | | `productAssignmentType` | string | Art der Produktzuordnung, z. B. `"manual"` (manuelle Zuordnung). | | `productRules` | string | Regeln für die automatische Produktzuordnung; leer bei manueller Zuordnung. | ### name und descr Name und Beschreibung sind die häufigsten Anzeigewerte. Mehr zur Konfiguration dieser Felder [in der Kategorie-Konfiguration](/konfiguration/content-katalog-kategorien-produkte#2-content-categoryfield-standard-kategoriefelder). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $category = $wsViews.current.info.category }} Kategoriename: {{= $category.name }} Beschreibung: {{= $category.descr }} ``` ### active Werten Sie `active` aus, um nur sichtbare Kategorien anzuzeigen, beispielsweise in einer Navigation. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $category.active == "always" }} {{ /if }} ``` ### hidden `hidden` blendet eine Kategorie gezielt aus der Navigation aus, ohne sie zu deaktivieren. Prüfen Sie es, bevor Sie einen Navigationseintrag erzeugen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if !$category.hidden }}
  • {{= $category.name }}
  • {{ /if }} ``` ### custom `custom` enthält die freien Felder der Kategorie. Anders als beim Produkt liegt das Kategoriebild unter `custom.image.category` (mit der WebP-Variante `custom.image.categoryWebp`); ein separates Navigationsbild liegt unter `custom.imageNavigation.category`. Prüfen Sie vor der Ausgabe, ob das gewünschte Feld vorhanden ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $category.custom.image.category }} {{= $category.name }} {{ /if }} ``` Neben den Bildern enthält `custom` unter anderem auch SEO-Felder (`metaTitle`, `metaDescription`, `seoName`) und Steuerungsfelder (`robotsNoIndex`, `robotsNoFollow`, `alternativeTemplate`). ### timestampCreatedAt und timestampUpdatedAt Beide liefern einen Zeitstempel als ISO-8601-String (UTC, z. B. `2026-05-07T13:09:08.000Z`). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Aktualisiert: {{= $category.timestampUpdatedAt }} ``` *** ## Methoden ### \$wsCategories.loadCategory() Lädt eine einzelne Kategorie anhand ihrer ID. Verwenden Sie die Methode, um gezielt eine bestimmte Kategorie anzuzeigen - auch außerhalb einer Kategorieseite, beispielsweise auf der Startseite oder in einem Blogbeitrag. **Signatur**\ `$wsCategories.loadCategory(categoryId)` **Rückgabe**\ `map` – Category-Map mit allen [Kategorie-Eigenschaften](#eigenschaften-einer-kategorie). **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ------------ | ------- | ----------- | ----------------------------- | | `categoryId` | string | ja | ID der zu ladenden Kategorie. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $category = $wsCategories.loadCategory("100-12345") }} {{= $category.name }} ``` ### \$wsCategories.loadChildren() Lädt die direkten Unterkategorien einer Kategorie. Nutzen Sie die Methode, um eine mehrstufige Navigation aufzubauen. **Signatur**\ `$wsCategories.loadChildren(parentId)` **Rückgabe**\ `array` – Liste von Category-Maps. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ---------- | ------- | ----------- | -------------------------------- | | `parentId` | string | nein | ID der übergeordneten Kategorie. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $child in $wsCategories.loadChildren("100-12345") }} {{= $child.name }} {{ /foreach }} ``` Ohne Angabe einer `parentId` werden die Kategorien der obersten Ebene zurückgegeben. Das ist nützlich, um die Hauptnavigation aufzubauen, ohne eine Wurzel-ID kennen zu müssen. ### \$wsCategories.loadPath() Lädt den Kategoriepfad (Breadcrumb) von der Wurzel bis zur angegebenen Kategorie. Verwenden Sie die Methode für eine Breadcrumb-Navigation, die dem Kunden zeigt, wo er sich befindet. **Signatur**\ `$wsCategories.loadPath(categoryId)` **Rückgabe**\ `array` – Liste von Category-Maps, von oben (Wurzel) nach unten (Zielkategorie). **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ------------ | ------- | ----------- | --------------------- | | `categoryId` | string | ja | ID der Zielkategorie. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $step in $wsCategories.loadPath($category.id) }} {{= $step.name }} / {{ /foreach }} ``` ### \$wsCategories.loadProducts() Lädt die Produkte, die in einer Kategorie enthalten sind. Nutzen Sie die Methode, um eine Produktliste außerhalb einer Kategorieseite aufzubauen (auf der Kategorieseite selbst liegen die Produkte bereits unter `$wsViews.current.info.products`). **Signatur**\ `$wsCategories.loadProducts(categoryId)` **Rückgabe**\ `array` – Liste von Produkt-Maps. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ------------ | ------- | ----------- | ------------------------------------------------ | | `categoryId` | string | ja | ID der Kategorie, deren Produkte geladen werden. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $products = $wsCategories.loadProducts("100-12345") }} {{ foreach $product in $products }} {{= $product.name }} {{ /foreach }} ``` ### \$wsCategories.loadCategoryMemberships() Lädt alle Kategorien, in denen ein bestimmtes Produkt enthalten ist. Nützlich, um auf einer Produktseite anzuzeigen, welchen Kategorien das Produkt zugeordnet ist. **Signatur**\ `$wsCategories.loadCategoryMemberships(productId)` **Rückgabe**\ `array` – Liste von Category-Maps. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | -------------------------------------------------- | | `productId` | string | ja | ID des Produkts, dessen Kategorien gesucht werden. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $category in $wsCategories.loadCategoryMemberships($product.id) }} {{= $category.name }} {{ /foreach }} ``` ### \$wsCategories.loadCategoryMembershipPaths() Lädt die vollständigen Kategoriepfade (Breadcrumbs) für alle Kategorien, in denen ein Produkt enthalten ist. Im Unterschied zu `loadCategoryMemberships()` erhalten Sie nicht nur die Zielkategorien, sondern jeweils den kompletten Pfad. Nützlich, um die vollständige Einordnung eines Produkts darzustellen. **Signatur**\ `$wsCategories.loadCategoryMembershipPaths(productId)` **Rückgabe**\ `array` – Liste von Pfaden, jeder Pfad ist selbst eine Liste von Category-Maps. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | ------------------------------------------------------ | | `productId` | string | ja | ID des Produkts, dessen Kategoriepfade gesucht werden. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $path in $wsCategories.loadCategoryMembershipPaths($product.id) }} {{ foreach $step in $path }} {{= $step.name }} > {{ /foreach }} {{ /foreach }} ``` *** ## Aktionen Für `$wsCategories` stehen keine Aktionen zur Verfügung. *** ## Beispiele Die Beispiele gehen davon aus, dass die anzuzeigende Kategorie zuvor einer Variablen zugewiesen wurde, beispielsweise auf einer Kategorieseite so: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $category = $wsViews.current.info.category }} ``` ### Name und Beschreibung anzeigen ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Kategoriename: {{= $category.name }} Kategoriebeschreibung: {{= $category.descr }} ``` **Ergebnis** \ Name und Beschreibung der aktuellen Kategorie werden ausgegeben. ### Kategoriebild anzeigen Prüfen Sie zuerst, ob ein Bild vorhanden ist, damit Sie kein leeres `img`-Tag erzeugen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $category.custom.image.category }} {{= $category.name }} {{ /if }} ``` **Ergebnis** \ Ist ein Übersichtsbild hinterlegt, wird es mit dem Kategorienamen als Alternativtext angezeigt. ### Unterkategorien anzeigen ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $child in $wsCategories.loadChildren($category.id) }}

    {{= $child.name }} – {{= $child.descr }}

    {{ /foreach }} ``` **Ergebnis** \ Alle direkten Unterkategorien der aktuellen Kategorie werden aufgelistet. ### Produkte der aktuellen Kategorie anzeigen Auf einer Kategorieseite liegen die Produkte der Kategorie bereits im Seitenkontext. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $product in $wsViews.current.info.products }} Produktname: {{= $product.name }} {{ /foreach }} ``` **Ergebnis** \ Die Produkte der aktuellen Kategorie werden ausgegeben. ### Breadcrumb der aktuellen Kategorie ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $step in $wsCategories.loadPath($category.id) }} {{= $step.name }} / {{ /foreach }} ``` **Ergebnis** \ Der Pfad von der obersten Kategorie bis zur aktuellen wird als Folge verlinkter Namen ausgegeben. ### Eine Kategorie auf einer beliebigen Seite laden Mit `loadCategory()` greifen Sie auch außerhalb einer Kategorieseite auf Kategoriedaten zu , beispielsweise auf der Startseite, in einem Blogbeitrag oder im Warenkorb. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $category = $wsCategories.loadCategory("101-12345") }} Kategoriename: {{= $category.name }} Kategoriebeschreibung: {{= $category.descr }} ``` **Ergebnis** \ Die angegebene Kategorie wird geladen und ihre Daten werden ausgegeben. Die in den Beispielen verwendeten IDs (`100-12345`, `101-12345`) sind Platzhalter und durch echte Kategorie-IDs Ihres Shops zu ersetzen. *** ## Weiterführende Links * [\$wsViews](/frontend/referenz/module/wsviews) – liefert über `current.info.category` und `current.info.products` die Daten der aktuellen Kategorieseite und mit `url('Category', {id})` die Kategorie-Links. * [Kategorie-Konfiguration](/konfiguration/content-katalog-kategorien-produkte#2-content-categoryfield-standard-kategoriefelder) – legt die Standard-Kategoriefelder (Name, Beschreibung, freie Felder) fest. ## ## # $wsCheckout - Checkout Source: https://dokumentation.websale.de/frontend/referenz/module/wscheckout Daten des Bestellvorgangs im Frontend lesen: Auswahl der Zahl- und Versandart, Adressen, Summen, Validierung und Fehler des aktuellen Checkouts. Mit dem `$wsCheckout`-Modul lesen Sie alle Daten des Bestellvorgangs im Frontend aus. Darunter die gewählte Zahlungs- und Versandart, Rechnungs- und Lieferadresse, die Bestellsummen sowie den Validierungs- und Fehlerstatus. Auf dieser Seite geht es um das Lesen der Checkout-Daten. Alles, was den Checkout **verändert** (Adresse wählen, Zahlungsart setzen, Bestellung auslösen), ist unter [Aktionen → Checkout](/frontend/referenz/aktionen/checkout) beschrieben. *** ## Grundkonzept Der Checkout sammelt die Auswahl des Kunden (Zahlung, Versand, Adressen, Freifelder) und prüft fortlaufend, ob die Bestellung ausführbar ist. Über `$wsCheckout` lesen Sie diese Auswahl und den Prüfstatus, um den Bestellablauf zu gestalten und dem Kunden gezielt Rückmeldung zu geben. ### Validierung Für das Prüf-Feedback gibt es drei Ebenen, die unterschiedlich genau sind. Wählen Sie die Ebene nach dem, was Sie anzeigen wollen: * **Gesamtstatus** - `isValid` gibt an, ob die Bestellung insgesamt ausführbar ist. Nutzen Sie es beispielsweise, um den „Kaufen"-Button freizugeben oder zu sperren. * **Feldzustand** - `fieldStates` liefert pro Feld einen Zustand (`untouched`, `empty`, `invalid`, `incompatible`, `valid`). Nutzen Sie es beispielsweise, um ein Feld optisch zu markieren. * **Konkrete Fehler** - `problems` liefert je Bereich eine Liste von Fehlern mit Fehler-Code und dem Namen des fehlgeschlagenen Checks. Nutzen Sie es beispielsweise, um dem Kunden zu sagen, wie der Fehler konkret zu lösen ist. ### Sofort-Fehler und Fehler nach einer Aktion Der Checkout kennt zwei Quellen für Fehler-Feedback: * `$wsCheckout.problems.*` - wird angezeigt, sobald ein Feld angewählt bzw. verlassen wurde, sofern `show*BeforeSubmit` in der [Konfiguration](/konfiguration/checkout-bestellablauf#7-checkout-fielderrorvisibility-fehleranzeige) auf `true` steht. Nach dem ersten Kaufversuch werden die Fehler unabhängig von dieser Einstellung angezeigt. * `actionResponse`-Fehler - stammen aus der Server-Antwort nach einer Aktion. Für die meisten Sektionen werden sie ungefiltert ausgegeben. Ausnahme: Bei Kundendatenfeldern und der [Draft-Adresse](/frontend/referenz/aktionen/checkout#checkoutsetdraftaddress) gibt es kein `problems.*`, dort werden die `actionResponse`-Fehler über `show*BeforeSubmit` gefiltert. ### Auswahl-IDs und Draft-Adressen Die `selected*`-Variablen enthalten die ID der jeweils gewählten Option (z. B. die Adress-ID, die Sie an [`$wsAccount.loadAddress()`](/frontend/referenz/module/wsAccount#wsaccount-loadaddress) übergeben). Legt der Kunde im Bestellablauf eine neue Adresse an, die noch nicht im Kundenkonto gespeichert ist (Draft-Adresse), wird sie unter einer **festen System-ID** geführt: `draftBillAddressId` bzw. `draftShippingAddressId`. Diese IDs sind **immer** vorhanden - auch wenn kein Entwurf existiert. Ob tatsächlich ein Entwurf vorliegt (und welche Daten er enthält), lesen Sie über die Maps [`draftBillAddress` / `draftShippingAddress`](#wscheckout-draftbilladdress-draftshippingaddress), die nur dann ausgegeben werden. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsCheckout` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsCheckout | json }} ``` **JSON-Ausgabe** (gekürzt) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountType": "...", "customerData": { }, "draftBillAddressId": "...", "draftShippingAddressId": "...", "fieldStates": { }, "freeFields": [...], "guestMail": "...", "ineffectiveVoucherErrors": [...], "isExpressCheckoutLocked": false, "isOrderBlockedByIneffectiveVoucher": false, "isPPCApplePayExpressCheckout": false, "isPPCExpressCheckout": false, "isPPCGooglePayExpressCheckout": false, "isValid": false, "paymentBlocked": false, "paymentCaptchaRequired": false, "paymentMethodAutoReset": false, "problems": { "billAddress": [...], "clearing": [...], "general": [...], "payment": [...], "shippingAddress": [...], "shippingMethod": [...] }, "selectedBillAddress": "...", "selectedPayment": "...", "selectedPseudoCC": "...", "selectedShippingAddress": "...", "selectedShippingMethod": "...", "selectedStoreId": 0, "shippingMethodAutoReset": false, "sum": { }, "useAlternativeShippingAddress": false, "verificationStatus": 0, "verificationStatusOptions": [...], "voucherAppliesPerItem": false, "getAmountInSmallestUnit": "ƒ()", "getShippingCost": "ƒ()", "getShippingMethodDisabledErrors": "ƒ()", "isFinished": "ƒ()", "isPending": "ƒ()", "isValidBillAddress": "ƒ()", "isValidPayment": "ƒ()", "hasPaymentVault": false, "isValidShippingAddress": "ƒ()", "isValidShippingMethod": "ƒ()", "itemVoucherDiscount": "ƒ()" } ``` Anmerkung: `"ƒ()"` kennzeichnet eine Funktion. Konditionale Variablen wie `orderId`, `orderCreatedAt`, `restUntilFreeDelivery`, `freeShippingMethod`, `draftBillAddress` und `draftShippingAddress` erscheinen nur, wenn sie gesetzt sind. **Variablen in der Übersicht** | **Variable** | **Rückgabe-Typ** | **Beschreibung** | | -------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `accountType` | string | Kontotyp: `"guest"`, `"new"` oder `"registered"`. Leer (`""`), solange noch kein Kontotyp gewählt wurde. | | `customerData` | map | Kundendaten-Felder, gruppiert und nach Zielgruppe aufgeteilt (u. a. `groupedFields`, `newCustomerFieldGroups`, `existingCustomerFieldGroups`; Struktur siehe unten). | | `freeFields` | array | Freie Checkout-Felder (Struktur siehe unten). | | `guestMail` | string | E-Mail eines Gastkontos. | | `selectedPayment` | string | ID der gewählten Zahlungsart. | | `selectedShippingMethod` | string | ID der gewählten Versandart. | | `selectedBillAddress` | string | ID der gewählten Rechnungsadresse. | | `selectedShippingAddress` | string | ID der gewählten Lieferadresse. | | `draftBillAddressId` | string | Feste System-ID, unter der eine Draft-Rechnungsadresse geführt wird. Immer vorhanden. | | `draftShippingAddressId` | string | Feste System-ID, unter der eine Draft-Lieferadresse geführt wird. Immer vorhanden. | | `draftBillAddress` | map | Daten der Draft-Rechnungsadresse. Nur vorhanden, wenn ein Entwurf existiert. | | `draftShippingAddress` | map | Daten der Draft-Lieferadresse. Nur vorhanden, wenn ein Entwurf existiert. | | `selectedPseudoCC` | string | Pseudo-Kreditkarten-Token. | | `selectedStoreId` | int | ID der gewählten Filiale (z. B. Click & Collect). | | `useAlternativeShippingAddress` | bool | Ob eine abweichende Lieferadresse aktiv ist. | | `orderId` | string | ID der Bestellung. Nur vorhanden, sobald in der Session eine Bestellung existiert. | | `orderCreatedAt` | string | Erstellzeitpunkt der Bestellung (ISO 8601). Nur vorhanden, sobald eine Bestellung existiert. | | `shippingMethodAutoReset`
    (**zukünftiges Feature**) | bool | Gibt aus, ob die Versandart automatisch neu gesetzt wurde, weil die zuvor gewählte Versandart durch eine Änderung des Bestellkontexts (z.B. Wechsel des Lieferlandes) ungültig geworden ist.
    Ob automatisch neu gewählt wird, steuert [`prevSelectionInvalidAutoSelect`](/konfiguration/checkout-bestellablauf). | | `paymentMethodAutoReset`
    (**zukünftiges Feature**) | bool | Gibt aus, ob die Zahlungsart automatisch neu gesetzt wurde, weil die zuvor gewählte Zahlungsart durch eine Änderung des Bestellkontexts (z.B. Wechsel des Lieferlandes) ungültig geworden ist.
    Ob automatisch neu gewählt wird, steuert [`prevSelectionInvalidAutoSelect`](/konfiguration/checkout-bestellablauf). | | `isValid` | bool | Prüft, ob die Bestellung insgesamt ausführbar ist. | | `isExpressCheckoutLocked` | bool | Prüft, ob der Express-Checkout gesperrt ist (z. B. nach PayPal-Zahlung). | | `isPPCExpressCheckout` | bool | Prüft, ob der PayPal-Commerce-Platform-Express-Checkout aktiv ist. | | `isPPCApplePayExpressCheckout` | bool | Prüft, ob Apple Pay Express Checkout aktiv ist. | | `isPPCGooglePayExpressCheckout` | bool | Prüft, ob Google Pay Express Checkout aktiv ist. | | `problems` | map | Konkrete Fehler je Bereich (Struktur siehe unten). | | `fieldStates` | map | Zustand je Checkout-Feld (Werte siehe unten). | | `sum` | map | Preisinformationen zum Checkout (Struktur siehe unten). | | `verificationStatus` | int | Verifizierungsstatus der Bestellung. | | `verificationStatusOptions` | array | Verfügbare Verifizierungsstatus-Optionen. | | `voucherAppliesPerItem` | bool | Prüft, ob Gutscheine pro Artikel angewendet werden. | | `restUntilFreeDelivery` | float | Verbleibender Betrag bis zur Grenze für kostenlosen Versand (`0`, wenn erreicht). Nur vorhanden, wenn für den Warenkorb eine Gratisversand-Grenze ermittelbar ist. | | `freeShippingMethod` | string | ID der Standard-Gratisversandart. Nur vorhanden, wenn `restUntilFreeDelivery` ausgegeben wird, noch keine Versandart gewählt ist und eine Standard-Gratisversandart konfiguriert wurde. | | `isOrderBlockedByIneffectiveVoucher` | bool | Prüft, ob die Bestellung durch einen wirkungslosen Gutschein blockiert ist. | | `ineffectiveVoucherErrors` | array | Fehler zu eingelösten Gutscheinen, die im aktuellen Warenkorb keine Wirkung entfalten. Leer, wenn alle Gutscheine greifen. | | `paymentBlocked` | bool | Prüft, ob die Zahlung blockiert ist (Schutz vor wiederholten Zahlungsversuchen, IP- oder Session-basiert). | | `paymentCaptchaRequired` | bool | Prüft, ob für die Zahlung ein Captcha erforderlich ist (Schutz vor wiederholten Zahlungsversuchen). | **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ----------------------------------- | ---------------- | ---------------------------------------------------------------------------- | | `isValidPayment()` | bool | Prüft, ob eine Zahlungsart verfügbar ist. | | `hasPaymentVault()` | bool | Prüft, ob für die im Checkout gewählte Zahlungsart eine Verknüpfung besteht. | | `isValidShippingMethod()` | bool | Prüft, ob eine Versandart verfügbar ist. | | `isValidBillAddress()` | bool | Prüft, ob eine Adresse als Rechnungsadresse gültig ist. | | `isValidShippingAddress()` | bool | Prüft, ob eine Adresse als Lieferadresse gültig ist. | | `isPending()` | bool | Prüft, ob ein Zahlungsvorgang aussteht. | | `isFinished()` | bool | Prüft, ob eine Bestellung abgeschlossen wurde. | | `getAmountInSmallestUnit()` | int | Wandelt einen Betrag in die kleinste Währungseinheit (z. B. Cent). | | `getShippingMethodDisabledErrors()` | array | Gibt zurück, warum eine Versandart deaktiviert ist. | | `getShippingCost()` | float | Versandkosten einer Versandart, bezogen auf den aktuellen Warenkorb. | | `itemVoucherDiscount()` | float | Berechnet den Gutscheinrabatt für einen Artikel. | *** ## Templates Der Checkout ist frei gestaltbar und kann eine oder mehrere Shopseiten umfassen. Die Reihenfolge der Elemente ist beliebig. *** ## Variablen ### \$wsCheckout.accountType Gibt den Kontotyp aus: `"guest"` (Gast), `"new"` (neues Konto) oder `"registered"` (angemeldet). Solange der Kunde noch keinen Kontotyp gewählt hat, ist der Wert leer (`""`). Werten Sie ihn aus, um beispielsweise einem Gast die Konto-Erstellung anzubieten. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.accountType == "guest" }} {{ /if }} ``` ### \$wsCheckout.guestMail Gibt die E-Mail-Adresse eines Gastkontos aus. Nur bei einer Gastbestellung gefüllt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} E-Mail: {{= $wsCheckout.guestMail }} ``` ### \$wsCheckout.selectedPayment / selectedShippingMethod Geben die ID der gewählten Zahlungs- bzw. Versandart aus. Werten Sie sie aus, um die getroffene Auswahl anzuzeigen oder zu prüfen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.selectedPayment == "stripe" }} {{ /if }} ``` ### \$wsCheckout.selectedBillAddress / selectedShippingAddress Geben die ID der gewählten Rechnungs- bzw. Lieferadresse aus. Diese ID übergeben Sie z. B. an [`$wsAccount.loadAddress()`](/frontend/referenz/module/wsAccount#wsaccount-loadaddress), um die vollständige Adresse zu laden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $billAddress = $wsAccount.loadAddress($wsCheckout.selectedBillAddress) }} {{= $billAddress.firstName }} {{= $billAddress.lastName }} ``` ### \$wsCheckout.draftBillAddressId / draftShippingAddressId Geben die **feste System-ID** aus, unter der eine im Bestellablauf neu angelegte, noch nicht im Kundenkonto gespeicherte Adresse (Draft-Adresse) geführt wird - z. B. um sie in der Adressauswahl als gewählte Adresse zu erkennen. Beide IDs sind **immer** vorhanden, unabhängig davon, ob ein Entwurf existiert. Ob tatsächlich ein Entwurf vorliegt, prüfen Sie über die Maps [`draftBillAddress` / `draftShippingAddress`](#wscheckout-draftbilladdress-draftshippingaddress). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.selectedBillAddress == $wsCheckout.draftBillAddressId }} {{ /if }} ``` ### \$wsCheckout.draftBillAddress / draftShippingAddress Geben die Daten der Draft-Rechnungs- bzw. Draft-Lieferadresse als Map aus. **Nur vorhanden, wenn ein Entwurf existiert** - damit eignen sie sich auch als Existenz-Prüfung. Die Keys entsprechen den Adressfeldnamen (Standardfelder wie `firstName`, `lastName`, `street`, `zip`, `city`, `country` sowie [zusätzliche Adressfelder](/konfiguration/accounts-benutzerkonten#accounts-customaddressfield-weitere-adressdatenfelder)). Ausgegeben werden nur Felder mit nicht-leerem Wert. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.draftBillAddress }} Neue Rechnungsadresse: {{= $wsCheckout.draftBillAddress.firstName }} {{= $wsCheckout.draftBillAddress.lastName }}, {{= $wsCheckout.draftBillAddress.street }}, {{= $wsCheckout.draftBillAddress.zip }} {{= $wsCheckout.draftBillAddress.city }} {{ /if }} ``` Eine Draft-Adresse wird über die Aktion [CheckoutSetDraftAddress](/frontend/referenz/aktionen/checkout#checkoutsetdraftaddress) angelegt. ### \$wsCheckout.useAlternativeShippingAddress Gibt aus, ob eine von der Rechnungsadresse abweichende Lieferadresse verwendet wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.useAlternativeShippingAddress }} {{ /if }} ``` ### \$wsCheckout.selectedStoreId Gibt die ID der gewählten Filiale aus (z. B. für Click & Collect). `0`, wenn keine Filiale gewählt ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.selectedStoreId > 0 }} {{ /if }} ``` ### \$wsCheckout.selectedPseudoCC Gibt den Pseudo-Kreditkarten-Token der gewählten Zahlung aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Token: {{= $wsCheckout.selectedPseudoCC }} ``` ### \$wsCheckout.orderId / orderCreatedAt Geben die ID und den Erstellzeitpunkt (ISO 8601) der Bestellung aus. Beide Variablen sind **nur vorhanden, sobald in der aktuellen Session eine Bestellung existiert** - z. B. auf der Bestellbestätigungsseite. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.orderId }} Ihre Bestellnummer: {{= $wsCheckout.orderId }} (erstellt: {{= $wsCheckout.orderCreatedAt }}) {{ /if }} ``` ### \$wsCheckout.customerData Gibt die konfigurierten Kundendaten-Felder aus - gruppiert und nach Zielgruppe aufgeteilt. Welche Felder enthalten sind, hängt vom Login-Status ab: Bei eingeloggten Kunden die Kontofelder, sonst die in der Bestellung gespeicherten Felder. #### Struktur von `$wsCheckout.customerData` | **Key** | **Typ** | **Beschreibung** | | ----------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `groupedFields` | array | Feldgruppen mit ihren Feldern (Struktur siehe Gruppen-Objekt). Immer vorhanden. | | `newCustomerFieldGroups` | array | Feldgruppen mit den Feldern für die [Neukundenregistrierung](/konfiguration/customer-kundendaten#customer-customerdatafieldsettings-feldkonfiguration). Immer vorhanden. | | `existingCustomerFieldGroups` | array | Feldgruppen mit den Feldern für die Bestandskundenregistrierung. Immer vorhanden. | | `ungroupedFields` | array | Felder ohne Gruppenzuordnung. Nur vorhanden, wenn `showUngroupedFields` in [`customer.customerDataFieldSettings`](/konfiguration/customer-kundendaten#customer-customerdatafieldsettings-feldkonfiguration) aktiv ist. | | `newCustomerFields` | array | Felder der Neukundenregistrierung als flache Liste. Nur vorhanden, wenn `showUngroupedFields` aktiv ist. | | `existingCustomerFields` | array | Felder der Bestandskundenregistrierung als flache Liste. Nur vorhanden, wenn `showUngroupedFields` aktiv ist. | #### Gruppen-Objekt Die Gruppen entsprechen der Konfiguration unter [`customer.customerDataGroup`](/konfiguration/customer-kundendaten#customer-customerdatagroup-gruppierung). | **Eigenschaft** | **Typ** | **Beschreibung** | | --------------- | ------- | ------------------------------------------------------------------------------------------------ | | `name` | string | Technischer Name der Gruppe. | | `label` | string | Anzeigename der Gruppe. | | `hidden` | bool | Ob die Gruppe ausgeblendet werden soll (u. a. `true`, wenn sie keine sichtbaren Felder enthält). | | `fields` | array | Die Felder der Gruppe (Struktur siehe Feld-Objekt). | #### Feld-Objekt | **Eigenschaft** | **Typ** | **Beschreibung** | | --------------- | ----------- | ----------------------------------------------------------------------------- | | `name` | string | Technischer Name des Feldes. | | `label` | string | Anzeigename des Feldes. | | `type` | string | Feldtyp (z. B. `text`, `number`, `date`, `checkbox`, `select`). | | `association` | string | Speicherort gemäß `storageStrategy` (Konto, Bestellung oder beides). | | `hidden` | bool | Ob das Feld ausgeblendet werden soll. | | `readonly` | bool | Ob das Feld schreibgeschützt ist. | | `touched` | bool | Ob das Feld vom Kunden bereits bearbeitet wurde. | | `required` | bool | Ob das Feld ein Pflichtfeld ist. | | `value` | string/bool | Aktueller Wert (bool bei `checkbox`, sonst string). | | `externalId` | string | Externe Kennung des Feldes. Nur vorhanden, wenn konfiguriert. | | `unit` | map | Einheiten-Informationen. Nur bei `number`-Feldern mit konfigurierter Einheit. | | `options` | array | Auswahloptionen (`{value, label}`). Nur bei `select`-Feldern. | **Beispiel,** das alle sichtbaren Feldgruppen mit ihren Feldern ausgibt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $group in $wsCheckout.customerData.groupedFields }} {{ if not $group.hidden }}
    {{= $group.label }} {{ foreach $field in $group.fields }} {{ if not $field.hidden }} {{ /if }} {{ /foreach }}
    {{ /if }} {{ /foreach }} ``` ### \$wsCheckout.freeFields Gibt die freien Checkout-Felder aus (z. B. AGB-Checkbox, Kommentarfeld). Iterieren Sie über die Felder und werten Sie sie über ihre `id` aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $field in $wsCheckout.freeFields }} {{= $field.name }} ({{= $field.type }}, Pflicht: {{= $field.required }}) {{ /foreach }} ``` #### Eigenschaften eines freien Feldes | **Eigenschaft** | **Rückgabe-Typ** | **Beschreibung** | | --------------- | ---------------- | ---------------------------------------------------------------------------------------------------- | | `id` | string | ID des Feldes (z. B. `"agb"`, `"comment"`). | | `name` | string | Anzeigename des Feldes (z. B. `"AGB"`). | | `type` | string | Feldtyp (`"checkbox"`, `"text"`). | | `required` | bool | Ob das Feld ein Pflichtfeld ist. | | `default` | bool/string | Standardwert (bool bei Checkbox, string bei Textfeld). | | `checked` | bool | Ob die Checkbox angehakt ist (nur bei `type == "checkbox"`). | | `text` | string | Aktuell eingegebener Text (nur bei `type == "text"` und nur vorhanden, wenn ein Wert gesetzt wurde). | ### \$wsCheckout.isValid Gibt aus, ob die Bestellung insgesamt ausführbar ist. Dies ist der Gesamtstatus über alle Felder – nutzen Sie ihn, um den „Kaufen"-Button frei- oder zu sperren. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.isValid }} {{ /if }} ``` ### \$wsCheckout.isExpressCheckoutLocked Gibt aus, ob der Express-Checkout gesperrt ist – z. B. nachdem der Kunde über PayPal bezahlt hat und zur Bestätigung in den Shop zurückgeleitet wird. Werten Sie es aus, um in diesem Zustand das Bearbeiten des Warenkorbs zu unterbinden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.isExpressCheckoutLocked }} Die Bearbeitung Ihres Warenkorbs ist derzeit nicht möglich. {{ /if }} ``` ### \$wsCheckout.isPPCExpressCheckout / isPPCApplePayExpressCheckout / isPPCGooglePayExpressCheckout Geben aus, ob der jeweilige Express-Checkout der PayPal Commerce Platform aktiv ist. Nutzen Sie sie, um den passenden Express-Checkout-Ablauf darzustellen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.isPPCExpressCheckout }} {{ /if }} ``` ### \$wsCheckout.paymentCaptchaRequired / paymentBlocked Schutz vor wiederholten Zahlungsversuchen (IP- oder Session-basiert): `paymentCaptchaRequired` gibt aus, ob vor dem nächsten Zahlungsversuch ein Captcha gelöst werden muss. `paymentBlocked` gibt aus, ob weitere Zahlungsversuche aktuell blockiert sind. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.paymentBlocked }} Zu viele fehlgeschlagene Zahlungsversuche. Bitte versuchen Sie es später erneut. {{ elseif $wsCheckout.paymentCaptchaRequired }} {{ /if }} ``` ### \$wsCheckout.isOrderBlockedByIneffectiveVoucher Gibt aus, ob die Bestellung blockiert ist, weil ein eingelöster Gutschein im aktuellen Warenkorb keine Wirkung entfalten kann. Nutzen Sie es, um den Bestellbutton zu sperren. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.isOrderBlockedByIneffectiveVoucher }} Ein eingelöster Gutschein kann auf diesen Warenkorb nicht angewendet werden. {{ /if }} ``` Das Flag meldet nur den Zustand. Um dem Kunden den konkreten Grund und den betroffenen Gutschein zu nennen, werten Sie zusätzlich [`ineffectiveVoucherErrors`](#wscheckout-ineffectivevouchererrors) aus. Ob die Bestellung überhaupt blockiert wird, steuert `disableOrderOnIneffectiveVoucher` in der [Checkout-Konfiguration](/konfiguration/checkout-bestellablauf#wirkungslose-gutscheine-blockieren). ### \$wsCheckout.ineffectiveVoucherErrors Gibt eine Liste der Fehler zu eingelösten Gutscheinen aus, die im aktuellen Warenkorb keine Wirkung entfalten. Jeder Eintrag nennt den Grund und, soweit zuordenbar, den betroffenen Gutschein. Damit ersetzen Sie einen allgemeinen Hinweis durch eine konkrete Aussage. Greifen alle Gutscheine, ist die Liste leer. Anders als bei [`problems`](#wscheckout-problems) enthalten diese Fehler bereits einen fertigen Text. Der Shop übersetzt dazu den Textbaustein, der im Konfigurationsknoten [`checkout.voucherErrors`](/konfiguration/checkout-bestellablauf#checkout-vouchererrors-fehlertexte-zu-wirkungslosen-gutscheinen) zum jeweiligen Fehlerfall hinterlegt ist. #### Eigenschaften eines Fehlers | **Eigenschaft** | **Rückgabe-Typ** | **Beschreibung** | | --------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `code` | string | Art des Fehlers (Werte siehe Tabelle unten). | | `subCode` | string | Feinere Unterteilung des Fehlers. Aktuell immer leer (`""`). | | `field` | string | Betroffenes Eingabefeld. Aktuell immer leer (`""`), weil in diesem Zusammenhang kein Eingabefeld beteiligt ist. | | `text` | string | Übersetzter Fehlertext aus `checkout.voucherErrors`. | | `details` | map | Zusatzangaben zum Fehler. Enthält den Key `voucherId` mit der ID des betroffenen Gutscheins, sofern der Fehler einem einzelnen Gutschein zuzuordnen ist. | `subCode` und `field` sind vorhanden, damit alle Fehlerobjekte im Frontend denselben Aufbau haben. Sie werden hier derzeit nicht gefüllt, können aber später Werte erhalten. Werten Sie sie deshalb nur aus, wenn sie tatsächlich gefüllt sind. #### Bedeutung der Fehler-Codes | **Code** | **Bedeutung** | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `"noValidProducts"` | Der Gutschein ist auf keine Position im Warenkorb anwendbar, beispielsweise weil er nur für bestimmte Produkte oder Kategorien gilt oder weil keine Position rabattfähig ist. | | `"minOrderValueNotReached"` | Der Mindestbestellwert für den Gutschein ist unterschritten. | Die Liste kann künftig weitere Codes enthalten. Sehen Sie im Template deshalb einen Fallback für unbekannte Codes vor, beispielsweise die Ausgabe von `text`. `details.voucherId` ist **nicht** in jedem Fehler enthalten. Steht `minOrderValueCalculation` auf `sum` und wird erst die Summe aller Mindestbestellwerte nicht erreicht, gehört der Fehler zu keinem einzelnen Gutschein und kommt ohne ID. Prüfen Sie den Key deshalb immer, bevor Sie ihn ausgeben. Welcher Fehler wann entsteht, steht unter [Wann welcher Fehler entsteht](/konfiguration/checkout-bestellablauf#wann-welcher-fehler-entsteht). **Beispiel,** das je Gutschein den konkreten Grund ausgibt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.isOrderBlockedByIneffectiveVoucher }}
    Gutscheine können nicht eingelöst werden:
      {{ foreach $cError in $wsCheckout.ineffectiveVoucherErrors }}
    • {{ if $cError.details.voucherId }} Gutschein {{= $cError.details.voucherId }}: {{ /if }} {{= $cError.text | ifNull($cError.code) }}
    • {{ /foreach }}
    {{ /if }} ``` **Ergebnis**
    Pro wirkungslosem Gutschein erscheint eine Zeile mit Gutschein-ID und Grund. Der Fehler aus der Summenprüfung erscheint als Zeile ohne ID. ### \$wsCheckout.verificationStatus / verificationStatusOptions `verificationStatus` gibt den Verifizierungsstatus der Bestellung als Zahl aus. `verificationStatusOptions` listet den möglichen Status auf. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $option in $wsCheckout.verificationStatusOptions }} {{= $option.id }}: {{= $option.name }} {{ /foreach }} ``` ### \$wsCheckout.voucherAppliesPerItem Gibt aus, ob ein Gutschein pro Artikel (statt auf den Gesamtbetrag) angewendet wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.voucherAppliesPerItem }} {{ /if }} ``` ### \$wsCheckout.restUntilFreeDelivery / freeShippingMethod `restUntilFreeDelivery` gibt den verbleibenden Betrag bis zur Grenze für kostenlosen Versand aus (`0`, wenn die Grenze erreicht ist). Die Variable ist **nur vorhanden, wenn für den Warenkorb eine Gratisversand-Grenze ermittelbar ist**. Nutzen Sie sie für einen Hinweis „Noch X bis zum kostenlosen Versand". `freeShippingMethod` enthält zusätzlich die ID der konfigurierten Standard-Gratisversandart - aber nur, solange der Kunde noch keine Versandart gewählt hat und eine Standard-Gratisversandart konfiguriert ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.restUntilFreeDelivery > 0 }} Nur noch {{= $wsCheckout.restUntilFreeDelivery | currency }} bis zum kostenlosen Versand! {{ /if }} ``` ### \$wsCheckout.fieldStates Gibt eine Map mit dem Zustand jedes Checkout-Feldes aus (`payment`, `shippingMethod`, `billAddress`, `shippingAddress`). Damit markieren Sie einzelne Felder gezielt – z. B. ein noch nicht ausgefülltes Feld neutral, ein fehlerhaftes rot. | **Wert** | **Beschreibung** | | ---------------- | ----------------------------------------------------------------- | | `"untouched"` | Das Feld wurde noch nicht bearbeitet oder ausgewählt. | | `"empty"` | Das Feld wurde befüllt, der Wert wurde aber wieder entfernt. | | `"invalid"` | Ein Wert ist vorhanden, hat die Validierung aber nicht bestanden. | | `"incompatible"` | Der Wert ist gültig, im aktuellen Kontext aber nicht zulässig. | | `"valid"` | Das Feld ist korrekt ausgefüllt und hat alle Prüfungen bestanden. | Die Zustände bauen aufeinander auf. Geprüft wird der Reihe nach: angewählt (`untouched`) → Wert vorhanden (`empty`) → gültig (`invalid`) → im Kontext zulässig (`incompatible`). Erst wenn alle Prüfungen bestanden sind, gilt das Feld als `valid`. Der erste zutreffende Zustand wird ausgegeben. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.fieldStates.payment == "valid" }} {{ /if }} ``` ### \$wsCheckout.problems Gibt eine Map mit konkreten Fehlern je Bereich aus. Die Map enthält genau sechs Bereiche: `payment`, `shippingMethod`, `billAddress`, `shippingAddress`, `clearing` und `general`. Jeder Bereich ist eine Liste von Fehlern; sie ist gefüllt, wenn dort ein Problem vorliegt. #### Eigenschaften eines Fehlers Jeder Fehler ist ein Objekt mit genau zwei Eigenschaften: | **Eigenschaft** | **Rückgabe-Typ** | **Beschreibung** | | --------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `code` | string | Fehler-Code (siehe Tabelle unten). | | `check` | string | Name des fehlgeschlagenen Validierungsservices (z. B. `"voucherDeny"`). Bei `code == "missing"` ist `check` `null`. Im Bereich `clearing` enthält `check` stattdessen die Fehlermeldung des Zahlungsproviders. | Einen sprechenden Fehlertext (`text`) oder das betroffene Feld (`field`) enthalten die Fehler-Objekte **nicht**. Formulieren Sie die Kundenmeldung im Template anhand von `code` und ggf. `check` (siehe Beispiel unten). #### Bedeutung der Fehler-Codes | **Code** | **Bedeutung** | **Beispiel** | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- | | `"missing"` | Kein Wert ausgewählt oder eingetragen. | Keine Zahlungsart gewählt. | | `"checkFailed"` | Ein Wert ist vorhanden, hat die Validierung aber nicht bestanden. | Ungültige Adresse; in `general`: unzulässiger Kontotyp (`check` = `"accountType"`). | | `"checkIncompatible"` | Der Wert ist gültig, im aktuellen Kontext aber nicht zulässig. | Zahlungsart für das Lieferland gesperrt. | | `"clearingFailed"` | Die Zahlungsabwicklung beim Provider ist fehlgeschlagen. Nur im Bereich `clearing`; `check` enthält die Fehlermeldung des Providers. | Zahlung von Computop abgelehnt. | **Beispiel,** das die Fehler der Zahlungsart kundenfreundlich ausgibt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $prob in $wsCheckout.problems.payment }} {{ if $prob.code == "missing" }} Bitte wählen Sie eine Zahlungsart aus. {{ elseif $prob.code == "checkFailed" }} Die gewählte Zahlungsart ist ungültig ({{= $prob.check }}). {{ elseif $prob.code == "checkIncompatible" }} Die gewählte Zahlungsart ist für Ihre Auswahl nicht verfügbar ({{= $prob.check }}). {{ /if }} {{ /foreach }} ``` Um auf einen einzelnen Fehler zuzugreifen, verwenden Sie den Index, z. B. `$wsCheckout.problems.payment[0].code`. Fehler zu freien Checkout-Feldern liefert `$wsCheckout.problems` nicht - diese werten Sie über die `actionResponse`-Fehler der jeweiligen Aktion aus (z. B. [CheckoutSetFreeFields](/frontend/referenz/aktionen/checkout)). ### \$wsCheckout.sum Gibt eine Map mit den Preisinformationen zum Checkout aus. Für die Anzeige als Geldbetrag verwenden Sie den `currency`-Filter – er enthält bereits das Währungssymbol. #### Eigenschaften von `$wsCheckout.sum` | **Eigenschaft** | **Rückgabe-Typ** | **Beschreibung** | | ------------------- | ---------------- | -------------------------------------------------------------- | | `total` | float | Gesamtbetrag der Bestellung (inkl. Versand, Rabatte, Steuern). | | `totalNet` | float | Nettobetrag. | | `totalGross` | float | Bruttobetrag. | | `totalTax` | float | Gesamte Mehrwertsteuer. | | `totalPreDeduction` | float | Gesamtbetrag vor dem Steuerabzug. | | `totalVoucher` | float | Wert der eingelösten Gutscheine. | | `totalWeight` | float | Gesamtgewicht der Bestellung. | | `shippingCost` | float | Versandkosten. | | `paymentCost` | float | Kosten der Zahlungsart. | | `surchargeCost` | float | Zusatzkosten / Aufschläge. | | `currency` | string | Währungscode (z. B. `"EUR"`). | | `totalTaxDeduction` | float | Betrag der abgezogenen Steuer (bei Steuerbefreiung). | | `isTaxExempt` | bool | Ob die Bestellung steuerbefreit ist. | | `usedExemptionRule` | string | Aktive Steuerprüfregel (z. B. `"shippingOnly"`). | | `billingCountry` | string | Länderkennung der Rechnungsadresse. | | `shippingCountry` | string | Länderkennung der Lieferadresse. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Gesamtbetrag: {{= $wsCheckout.sum.total | currency }} Versandkosten: {{= $wsCheckout.sum.shippingCost | currency }} ``` *** ## Methoden ### \$wsCheckout.isValidPayment() Prüft, ob die Zahlungsart mit der angegebenen ID verfügbar ist. Dabei werden alle Validierungsregeln ausgeführt, die in der Konfiguration der Zahlungsart unter `validations` hinterlegt sind (siehe [`paymentValidation.*` - Zahlungsarten-Validierung](/konfiguration/validierungs-und-prufservices#paymentvalidation-%2A-zahlungsarten-validierung)) - z.B. Länderregeln, Bestellwertgrenzen oder der Ausschluss bei Gutscheinprodukten im Warenkorb (`paymentValidation.voucherDeny`). Zusätzlich wird geprüft, ob die Zahlungsart aktiv und für das Kundenkonto zugelassen ist. Schlägt mindestens eine Regel fehl, gibt die Methode `false` zurück. Auf diese Weise wirken die konfigurierten Validierungsregeln im Frontend: Das Template blendet die Zahlungsart aus oder deaktiviert sie. **Signatur**
    `$wsCheckout.isValidPayment(paymentId)` **Rückgabe**
    `true / false` - Zahlungsart verfügbar / nicht verfügbar. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | -------------------------------------------- | | `paymentId` | string | ja | ID der Zahlungsart, die geprüft werden soll. | **Beispiel,** das prüft, ob die Zahlungsart verfügbar ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.isValidPayment("stripe") }} // Stripe ist verfügbar {{ /if }} ``` **Beispiel,** das alle Zahlungsarten als Auswahl anbietet und nicht verfügbare Zahlungsarten deaktiviert. Zahlungsarten, deren Validierung fehlschlägt (z.B. wegen `paymentValidation.voucherDeny` bei einem Gutscheinprodukt im Warenkorb), sind sichtbar, aber nicht wählbar. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $cPayment in $wsConfig.payments }} {{ /foreach }} ``` Warum die aktuell ausgewählte Zahlungsart ungültig ist, lässt sich über [`$wsCheckout.problems.payment`](#wscheckout-problems) auswerten; das Feld `check` enthält dort den Namen des fehlgeschlagenen Validierungsservices. ### \$wsCheckout.hasPaymentVault() Prüft, ob für den angemeldeten Kunden eine Verknüpfung mit dem Zahlungsanbieter besteht, bezogen auf die im Checkout aktuell gewählte Zahlungsart. Besteht eine Verknüpfung, wird die Bestellung direkt darüber bezahlt und der Kunde muss die Freigabe nicht erneut beim Zahlungsanbieter durchlaufen. Nutzen Sie diese Methode, um im Checkout entweder die gespeicherte Zahlungsquelle anzuzeigen oder das Angebot zur Verknüpfung einzublenden. Die Methode gibt in allen Zweifelsfällen den Wert`false` zurück: wenn keine Zahlungsart gewählt wurde, wenn die gewählte Zahlungsart keine Verknüpfung unterstützt oder wenn der Kunde nicht angemeldet ist. **Signatur**
    `$wsCheckout.hasPaymentVault()` **Rückgabe**
    `true / false` - Verknüpfung vorhanden / nicht vorhanden. **Beispiel,** das im Checkout zwischen gespeicherter Verknüpfung und Neu-Verknüpfung unterscheidet. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.hasPaymentVault() }} {{ else }} {{ /if }} ``` Für eine Prüfung außerhalb des Checkouts, beispielsweise auf einer Seite im Kundenkonto, auf der die Verknüpfung verwaltet wird, verwenden Sie die Methode [\$wsAccount.hasPaymentVault()](/frontend/referenz/module/wscheckout#wsaccount-haspaymentvault). Diese Methode erwartet die Zahlungsart als Parameter. ### \$wsCheckout.isValidShippingMethod() Prüft, ob die Versandart mit der angegebenen ID verfügbar ist. Dabei werden alle Validierungsregeln ausgeführt, die in der Konfiguration der Versandart unter `validations` hinterlegt sind (siehe [`shippingMethodValidation.*` - Versandarten-Validierung](/konfiguration/validierungs-und-prufservices#shippingmethodvalidation-%2A-versandarten-validierung)) - z.B. Länderregeln, Warenwertgrenzen oder Produkttyp-Beschränkungen. Schlägt mindestens eine Regel fehl, gibt die Methode `false` zurück. Das Template blendet die Versandart dann aus oder deaktiviert sie (gleiches Muster wie bei [`isValidPayment()`](#wscheckout-isvalidpayment)). Die Gründe für eine deaktivierte Versandart lassen sich über [`getShippingMethodDisabledErrors()`](#wscheckout-getshippingmethoddisablederrors) ausgeben. **Signatur**
    `$wsCheckout.isValidShippingMethod(shippingMethodId)` **Rückgabe**
    `true / false` - Versandart verfügbar / nicht verfügbar. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ------------------ | ------- | ----------- | ------------------------------------------- | | `shippingMethodId` | string | ja | ID der Versandart, die geprüft werden soll. | **Beispiel,** das prüft, ob die angegebene Versandart verfügbar ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.isValidShippingMethod("dhl_standard") }} // DHL Standard ist verfügbar {{ /if }} ``` ### \$wsCheckout.isValidBillAddress() / isValidShippingAddress() Prüfen, ob die Adresse mit der angegebenen ID als Rechnungs- bzw. Lieferadresse gültig ist. **Signatur**
    `$wsCheckout.isValidBillAddress(addressId)` · `$wsCheckout.isValidShippingAddress(addressId)` **Rückgabe**
    `bool` – gültig / nicht gültig. | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | ---------------------------- | | `addressId` | string | ja | ID der zu prüfenden Adresse. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.isValidBillAddress($wsCheckout.selectedBillAddress) }} {{ /if }} ``` ### \$wsCheckout.isPending() / isFinished() `isPending()` prüft, ob ein Zahlungsvorgang noch aussteht, `isFinished()`, ob die Bestellung abgeschlossen wurde. Nutzen Sie sie, um den Status einer laufenden oder abgeschlossenen Bestellung zu erkennen. **Signatur**
    `$wsCheckout.isPending()` · `$wsCheckout.isFinished()` **Rückgabe**
    `bool`. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.isPending() }} {{ /if }} ``` ### \$wsCheckout.getAmountInSmallestUnit() Gibt einen Betrag in der kleinsten Währungseinheit zurück (z. B. Cent statt Euro). Nützlich für Zahlungs-APIs, die Beträge in Cent erwarten. **Signatur**
    `$wsCheckout.getAmountInSmallestUnit(amount)` **Rückgabe**
    `int` – Betrag in kleinster Einheit. | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | -------- | ------- | ----------- | --------------------------- | | `amount` | float | ja | Betrag in der Hauptwährung. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cents = $wsCheckout.getAmountInSmallestUnit($wsCheckout.sum.total) }} ``` ### \$wsCheckout.getShippingMethodDisabledErrors() Gibt zurück, warum eine Versandart deaktiviert ist. Nutzen Sie es, um dem Kunden zu erklären, weshalb eine Versandart nicht wählbar ist. **Signatur**
    `$wsCheckout.getShippingMethodDisabledErrors(shippingMethodId)` **Rückgabe**
    `array` – Liste mit Fehlermeldungen. | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ------------------ | ------- | ----------- | ------------------------------- | | `shippingMethodId` | string | ja | ID der zu prüfenden Versandart. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $error in $wsCheckout.getShippingMethodDisabledErrors("express") }} {{= $error }} {{ /foreach }} ``` ### \$wsCheckout.getShippingCost() Gibt die Versandkosten einer bestimmten Versandart zurück. Auch dann, wenn diese nicht ausgewählt ist. Der Wert bezieht sich auf den aktuellen Warenkorb. Nutzen Sie es beispielsweise, um die Versandkosten verschiedener Optionen vorab anzuzeigen. **Signatur**
    `$wsCheckout.getShippingCost(shippingMethodId)` **Rückgabe**
    `float` – Versandkosten der angegebenen Versandart. | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ------------------ | ------- | ----------- | ------------------------------------------------- | | `shippingMethodId` | string | ja | ID der Versandart, deren Kosten ermittelt werden. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Versandkosten: {{= $wsCheckout.getShippingCost("dhl_standard") | currency }} ``` ### \$wsCheckout.itemVoucherDiscount() Berechnet den Gutscheinrabatt für einen einzelnen Warenkorb-Artikel. Übergeben Sie die ID eines [Warenkorb-Eintrags](/frontend/referenz/module/wsbasket#wsbasket-items). **Signatur**
    `$wsCheckout.itemVoucherDiscount(itemId)` **Rückgabe**
    `float` – Rabattbetrag für den Artikel. | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | -------- | ------- | ----------- | -------------------------- | | `itemId` | string | ja | ID des Warenkorb-Eintrags. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Rabatt: {{= $wsCheckout.itemVoucherDiscount($item.id) | currency }} ``` *** ## Aktionen Aktionen, die den Checkout verändern (Adresse wählen, Zahlungsart setzen, Bestellung auslösen), sind separat dokumentiert: [Aktionen → Checkout](/frontend/referenz/aktionen/checkout). *** ## Beispiele ### Bestellbarkeit prüfen und Fehler anzeigen Dieses Beispiel kombiniert die Validierungsebenen:
    Ist die Bestellung gültig, wird der „Kaufen"-Bereich angezeigt, sonst werden die konkreten Probleme aufgelistet - anhand von `code` und `check`, da die Fehler-Objekte keinen fertigen Text enthalten. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.isValid }} {{ else }} {{ foreach $prob in $wsCheckout.problems.payment }} {{ if $prob.code == "missing" }} Bitte wählen Sie eine Zahlungsart aus. {{ else }} Die gewählte Zahlungsart ist nicht verfügbar ({{= $prob.check }}). {{ /if }} {{ /foreach }} {{ foreach $prob in $wsCheckout.problems.shippingMethod }} {{ if $prob.code == "missing" }} Bitte wählen Sie eine Versandart aus. {{ else }} Die gewählte Versandart ist nicht verfügbar ({{= $prob.check }}). {{ /if }} {{ /foreach }} {{ foreach $prob in $wsCheckout.problems.billAddress }} Bitte prüfen Sie Ihre Rechnungsadresse ({{= $prob.code }}). {{ /foreach }} {{ /if }} ``` **Ergebnis**
    Bei gültiger Bestellung erscheint der Kaufen-Bereich, sonst die offenen Punkte je Bereich. ### Summenübersicht Eine vollständige Summenanzeige. Der `currency`-Filter enthält das Währungssymbol bereits. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Zwischensumme: {{= $wsCheckout.sum.totalNet | currency }} Versandkosten: {{= $wsCheckout.sum.shippingCost | currency }} Mehrwertsteuer: {{= $wsCheckout.sum.totalTax | currency }} {{ if $wsCheckout.sum.totalVoucher > 0 }} Gutschein: {{= $wsCheckout.sum.totalVoucher | currency }} {{ /if }} Gesamtbetrag: {{= $wsCheckout.sum.total | currency }} ``` **Ergebnis**
    Eine aufgeschlüsselte Summenübersicht mit korrekt formatierten Geldbeträgen. ### AGB-Zustimmung prüfen Prüft, ob das Freifeld `agb` angehakt ist, bevor die Bestellung erlaubt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $field in $wsCheckout.freeFields }} {{ if $field.id == "agb" and not $field.checked }} Bitte akzeptieren Sie die AGB. {{ /if }} {{ /foreach }} ``` **Ergebnis**
    Ist die AGB-Checkbox nicht angehakt, erscheint der Hinweis. ### Gewählte Zahlungsart prüfen ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.isValidPayment($wsCheckout.selectedPayment) }} Gewählte Zahlungsart: {{= $wsCheckout.selectedPayment }} {{ /if }} ``` **Ergebnis**
    Die gewählte Zahlungsart wird angezeigt, sofern sie gültig ist. *** ## Weiterführende Links * [Aktionen → Checkout](/frontend/referenz/aktionen/checkout) – den Checkout verändern (Auswahl setzen, Bestellung auslösen), weil `$wsCheckout` selbst nur liest. * [\$wsBasket](/frontend/referenz/module/wsbasket) – der Warenkorb, auf dem der Checkout aufbaut; liefert die Artikel für `itemVoucherDiscount()`. * [\$wsAccount](/frontend/referenz/module/wsAccount) – lädt über `loadAddress()` die vollständige Adresse zur `selectedBillAddress`/`selectedShippingAddress`. * [Checkout-Konfiguration](/konfiguration/checkout-bestellablauf#7-checkout-fielderrorvisibility-fehleranzeige) – steuert mit `show*BeforeSubmit`, wann Fehler angezeigt werden. * [Fehlertexte zu wirkungslosen Gutscheinen](/konfiguration/checkout-bestellablauf#checkout-vouchererrors-fehlertexte-zu-wirkungslosen-gutscheinen) – pflegt die Texte, die `ineffectiveVoucherErrors` ausgibt. * [\$wsVoucher](/frontend/referenz/module/wsvoucher) – die eingelösten Gutscheine selbst, passend zu den IDs aus `ineffectiveVoucherErrors`. # $wsCmsPage - CMS-Seite ausgeben Source: https://dokumentation.websale.de/frontend/referenz/module/wscmspage Modul $wsCmsPage: das Seitendokument einer CMS-Seite aus strapi im Template lesen. Mit dem `$wsCmsPage` Modul können Sie im Template auf das Seitendokument der aktuell aufgerufenen CMS-Seite zugreifen. Das Modul liefert das JSON-Dokument aus dem Objektspeicher unverändert aus, ohne Umbenennung oder Umsortierung. Ein typischer Anwendungsfall ist das CMS-Seitentemplate, das die Inhalte einer in Strapi gepflegten Inhaltsseite ausgibt. Das Modul wird ausschließlich auf CMS-Seiten gefüllt, also auf Seiten, die über den View-Controller `CmsPage` gerendert werden. Auf allen anderen Seiten ist `$wsCmsPage` leer (`null`). Weiterführende Seiten zu diesem Thema: * [Auslieferung von CMS-Seiten in den Shop](/strapi-cms/grundlagen-architektur-von-strapi#auslieferung-von-cms-seiten-in-den-shop) erklärt, wie die Seiten in den Objektspeicher kommen, wie die SEO-URL entsteht und welche Felder der Shop selbst auswertet. * [Template Theme](/frontend/die-basics/template-theme#cms-seitentemplate) erklärt das CMS-Seitentemplate und die Einbindung in das Basis-Template. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsCmsPage` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsCmsPage | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "contentType": "api::contentpage.contentpage", "meta": { "id": 92, "documentId": "jyllb6ubw0dj62vndr0lh7z1", "locale": "de", "createdAt": "2026-06-26T08:00:00.000Z", "updatedAt": "2026-07-16T09:00:00.000Z", "publishedAt": "2026-07-16T09:03:00.000Z", "url": "Zahlungsarten", "metaTitle": "Zahlungsarten", "metaDescription": "Beschreibung zu Zahlungsarten", "robots": ["noindex", "nofollow"], "hreflang": [ { "language": "fr-fr", "url": "myshop.fr/paiement", "subshopId": "francais", "default": false } ] }, "fields": [ { "name": "Markup", "type": "richtext", "value": "AGB Content" }, { "name": "content", "type": "dynamiczone", "value": [ { "component": "elemente.ws-markup", "id": 96, "fields": [ { "name": "FullWidth", "type": "boolean", "value": false } ] } ] } ] } ``` **Variablen in der Übersicht** | **Name** | **Rückgabe-Typ** | **Beschreibung** | | ----------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------- | | `contentType` | string | strapi-Kennung des Content-Typs, aus dem die Seite stammt. Wird vom Shop nicht ausgewertet. | | `meta` | map | Verwaltungsdaten der Seite plus SEO-Block. | | `meta.url` | string | URL der Seite, ohne führenden Schrägstrich. | | `meta.metaTitle` | string | Meta-Title. Wird vom Shop zusätzlich als Seitentitel gesetzt und ist über `$wsViews.metaTitle()` verfügbar. | | `meta.metaDescription` | string | Meta-Description. Wird vom Shop zusätzlich gesetzt und ist über `$wsViews.metaDescription()` verfügbar. | | `meta.robots` | array | Robots-Angaben der Seite. Werden vom Shop zusätzlich in `$wsViews.current.robotOptions` zusammengeführt. | | `meta.publishedAt` | string oder null | Zeitstempel der Veröffentlichung. `null` bei Entwürfen. | | `meta.hreflang` | array | Alternativsprachen-Objekte (`language`, `url`, `subshopId`, `default`). Werden **nicht** automatisch ausgegeben. | | `meta.id` | number | Interne numerische strapi-ID (pro Sprachversion). | | `meta.documentId` | string | Stabile, sprachübergreifende Dokument-ID. | | `meta.locale` | string | Sprache des Dokuments, beispielsweise `de`. | | `meta.createdAt` / `meta.updatedAt` | string (ISO-8601) | Zeitstempel aus strapi. | | `fields` | array | Die Inhaltsfelder der Seite, je `{ name, type, value }`. Unverändert aus strapi. | ## Methoden Für `$wsCmsPage` stehen keine Methoden zur Verfügung. *** ## Variablen ### \$wsCmsPage.contentType Gibt aus, aus welchem strapi-Content-Typ die aufgerufene Seite stammt. Der Content-Typ entspricht der Eingabemaske hinter der Seite und legt fest, welche Felder ein Redakteur ausfüllen kann. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsCmsPage.contentType }} ``` ### \$wsCmsPage.meta Enthält die Verwaltungsdaten und den SEO-Block der Seite. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsCmsPage.meta | json }} ``` Der Shop setzt Meta-Title und Meta-Description bereits selbst. Im Basis-Template werden sie üblicherweise über die Funktionen [\$wsViews.metaTitle()](https://dokumentation.websale.de/frontend/referenz/module/wsviews#\$wsviews-metatitle) und [\$wsViews.metaDescription()](https://dokumentation.websale.de/frontend/referenz/module/wsviews#\$wsviews-metadescription) ausgegeben, damit alle Seitentypen einheitlich behandelt werden. Der direkte Zugriff über `$wsCmsPage.meta` ist nur nötig, wenn Sie die Rohwerte an anderer Stelle benötigen. Welche dieser Felder der Shop auswertet und welche Felder reine Verwaltungsdaten sind, steht unter [Der SEO-Block in meta](/strapi-cms/grundlagen-architektur-von-strapi#der-seo-block-in-meta). ### \$wsCmsPage.fields Enthält die Inhaltsfelder der Seite. Jeder Eintrag hat die Schlüssel `name`, `type` und `value`. Der Shop gibt diese Liste unverändert weiter und interpretiert sie nicht. Welche Feldnamen und Komponenten es gibt, ergibt sich aus der Strapi-Modellierung des jeweiligen Shops. Für den Zugriff wird die Liste einmalig in ein Name/Wert-Objekt überführt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCmsPage }} {{ var $cFields = {} }} {{ foreach $cField in $wsCmsPage.fields }} {{ $cFields[$cField.name] = $cField.value }} {{ /foreach }}

    {{= $wsCmsPage.meta.metaTitle }}

    {{! $cFields.Markup }}
    {{ /if }} ``` Das Muster gilt auf jeder Ebene, auch innerhalb von Komponenten (`value.fields`) und für die Blöcke von Inhaltsblöcken. Die Feldtypen und die Form der jeweiligen `value` sind unter [Die Feldtypen](/strapi-cms/migration-der-strapi-datenstruktur-v5#die-feldtypen) beschrieben, das Umstellen bestehender Feldzugriffe unter [Schritt 4](/strapi-cms/migration-der-strapi-datenstruktur-v5#schritt-4-feldzugriffe-umstellen) und [Schritt 5](/strapi-cms/migration-der-strapi-datenstruktur-v5#schritt-5-inhaltsblocke-dynamic-zone-anpassen). Die Reihenfolge der `fields`-Liste folgt der Schema-Definition und ist für das Rendern bedeutungslos. Greifen Sie deshalb immer über `name` und nie über die Position auf Felder zu. Die Reihenfolge **innerhalb** eines Array-Werts (Inhaltsblöcke, wiederholbare Komponenten) entspricht dagegen exakt der Anordnung des Redakteurs und muss beim Rendern übernommen werden. *** ## Aktionen Für `$wsCmsPage` stehen keine Aktionen zur Verfügung. *** ## Beispiele ### Gemeinsames Basis-Template auf CMS-Inhalte prüfen Da `$wsCmsPage` auf allen anderen Seiten `null` ist, kann ein gemeinsames Basis-Template gefahrlos darauf prüfen: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCmsPage }} {{# nur auf CMS-Seiten #}} {{ /if }} ``` ### Alternativsprachen ausgeben `meta.hreflang` wird nicht automatisch in die hreflang-Angaben des Shops übernommen,[\$wsViews.current.getHreflangAutomatic()](https://dokumentation.websale.de/frontend/referenz/module/wsviews#\$wsviews-current-gethreflangautomatic) liefert für CMS-Seiten nichts. Für die Ausgabe im HTML-Head: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $cAlt in $wsCmsPage.meta.hreflang }} {{ /foreach }} ``` ### Unbekannte Komponenten im Testmodus sichtbar machen Ohne einen `{{ else }}`-Zweig verschwindet eine neu angelegte, im Template nicht umgesetzte Komponente still aus der Seite: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $cItem in $cFields.content }} {{ if $cItem.component == "elemente.ws-markup" }} {{# … Ausgabe … #}} {{ else }} {{ if $wsTestMode.active }} {{ /if }} {{ /if }} {{ /foreach }} ``` ### Entwurf im Testmodus kennzeichnen Ein Entwurf (`meta.publishedAt` ist `null`) wird nur bei aktivem [Testmodus](/frontend/referenz/aktionen/testmode) ausgeliefert. Das lässt sich im Template sichtbar machen: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCmsPage && !$wsCmsPage.meta.publishedAt }}

    Diese Seite ist ein Entwurf und öffentlich nicht erreichbar.

    {{ /if }} ``` *** ## Weiterführende Links * [Auslieferung von CMS-Seiten in den Shop](/strapi-cms/grundlagen-architektur-von-strapi#auslieferung-von-cms-seiten-in-den-shop) * [Template Theme - CMS-Seitentemplate](/frontend/die-basics/template-theme#cms-seitentemplate) * [content.cmsTemplates](/konfiguration/content-katalog-kategorien-produkte#content-cmstemplates-cms-seiten) * [Migration der strapi-Datenstruktur (Version 5)](/strapi-cms/migration-der-strapi-datenstruktur-v5) * [\$wsViews](/frontend/referenz/module/wsviews) * [\$wsTestMode](/frontend/referenz/module/wstestmode) # $wsComputopHosted - Computop (gehostete Bezahlseite) Source: https://dokumentation.websale.de/frontend/referenz/module/wscomputophosted Daten für die Weiterleitung zur gehosteten Computop-Bezahlseite bereitstellen und Rückkehr sowie Zahlungsergebnis im Frontend auswerten. Mit dem `$wsComputopHosted`-Modul wickeln Sie Zahlungen über die gehostete Computop-Bezahlseite ab. Das Modul liefert alle Daten, die Sie brauchen, um den Kunden per Formular zur Computop-Bezahlseite weiterzuleiten, und meldet nach der Rückkehr, ob die Zahlung erfolgreich war. Auf dieser Seite geht es um das Bereitstellen der Formulardaten und das Auswerten des Ergebnisses. Die eigentliche Zahlungsabwicklung läuft auf der Computop-Seite, die Konfiguration der Schnittstelle (Händler-ID, Schlüssel) erfolgt in der Zahlungs-Konfiguration. *** ## Grundkonzept Bei einer gehosteten Bezahlseite findet die Zahlung nicht im Shop statt, sondern auf einer Seite des Zahlungsdienstleisters. `$wsComputopHosted` liefert die Daten, mit denen Sie den Kunden dorthin weiterleiten. Der Ablauf ist immer derselbe: Formular bauen → absenden → Computop wickelt ab → Rückkehr auswerten. 1. Sie bauen ein HTML-Formular, dessen `action` auf [`$wsComputopHosted.action`](#wscomputophosted-action) zeigt, und legen die übrigen Werte (`data`, `len`, `merchantID`, `encryptionType` …) als versteckte Felder ab. 2. Der Kunde sendet das Formular ab und gelangt auf die Computop-Bezahlseite. 3. Computop wickelt die Zahlung ab und leitet den Kunden zurück in den Shop. 4. Nach der Rückkehr werten Sie [`paymentCanceled`](#wscomputophosted-paymentcanceled), [`paymentFailed`](#wscomputophosted-paymentfailed) und [`error`](#wscomputophosted-error) aus, um dem Kunden eine passende Rückmeldung zu geben. ### Verschlüsselte Daten unverändert durchreichen Die Felder `data`, `len` und `encryptionType` bilden die verschlüsselten Zahlungsdaten. Sie berechnen daran nichts selbst und verändern sie nicht, sie reichen die Werte unverändert an Computop weiter. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsComputopHosted` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsComputopHosted | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "action": "", "data": "", "encryptionType": "AES", "error": "", "freeFields": [], "language": "", "len": "0", "merchantID": "", "payType": "", "paymentCanceled": false, "paymentFailed": false, "template": "" } ``` **Anmerkung:** Konditionale Variablen erscheinen nur, wenn sie gesetzt sind: `hideSave`, `prefill` sowie die Daten einer gespeicherten Kreditkarte (`PCNr`, `PCNrBrand`, `PCNrYear`, `PCNrMonth`, `holder`). **Variablen zum Aufbau des Formulars** | **Variable** | **Typ** | **Beschreibung** | | ---------------- | ------- | --------------------------------------------------------------------------------------------- | | `action` | string | URL der Computop-Bezahlseite (als `action` des Formulars). | | `data` | string | Verschlüsselte Zahlungsdaten. | | `len` | string | Länge der verschlüsselten Daten (zur Prüfung bei Computop). | | `encryptionType` | string | Verschlüsselungstyp: `"Blowfish"` oder `"AES"`. | | `merchantID` | string | Händler-ID bei Computop. | | `payType` | string | Zahlungsart (z. B. Kreditkarte). | | `language` | string | Sprachcode für die Bezahlseite (z. B. `"de"`). | | `template` | string | Name des Computop-Templates. | | `hideSave` | string | Enthält `"hideSave"`, wenn die Speichern-Option ausgeblendet werden soll. Nur dann vorhanden. | | `prefill` | string | Enthält `"on"`, wenn die Speichern-Option vorbelegt (angehakt) sein soll. Nur dann vorhanden. | | `freeFields` | array | Freie Checkout-Felder, die an Computop übermittelt werden (Struktur siehe unten). | **Variablen einer gespeicherten Kreditkarte** (nur vorhanden, wenn eine gespeicherte Pseudo-Kreditkarte gewählt ist) | **Variable** | **Typ** | **Beschreibung** | | ------------ | ------- | ---------------------------------------------------- | | `PCNr` | string | Pseudo-Kartennummer (Token) der gespeicherten Karte. | | `PCNrBrand` | string | Kartenmarke (z. B. Visa). | | `PCNrYear` | string | Ablaufjahr der Karte. | | `PCNrMonth` | string | Ablaufmonat der Karte. | | `holder` | string | Karteninhaber. | **Variablen zum Auswerten des Ergebnisses** | **Variable** | **Typ** | **Beschreibung** | | ----------------- | ------- | -------------------------------------------- | | `paymentCanceled` | bool | `true`, wenn die Zahlung abgebrochen wurde. | | `paymentFailed` | bool | `true`, wenn die Zahlung fehlgeschlagen ist. | | `error` | string | Fehlermeldung bei einem Zahlungsproblem. | *** ## Templates Das Weiterleitungsformular wird typischerweise im Checkout eingebunden, also auf der Seite, von der aus der Kunde zur Zahlung weitergeleitet wird. Die Ergebnis-Variablen werten Sie auf der Seite aus, auf die Computop nach der Zahlung zurückleitet. *** ## Variablen ### \$wsComputopHosted.action Gibt die URL der Computop-Bezahlseite aus. Sie verwenden sie als `action`-Attribut des Formulars, mit dem der Kunde zur Zahlung weitergeleitet wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
    ...
    ``` ### \$wsComputopHosted.data Gibt die verschlüsselten Zahlungsdaten aus. Sie übermitteln sie als verstecktes Formularfeld – unverändert (siehe [Grundkonzept](#verschlüsselte-daten-unverändert-durchreichen)). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` ### \$wsComputopHosted.len Gibt die Länge der verschlüsselten Daten aus. Computop benötigt diesen Wert, um die übermittelten Daten zu prüfen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` ### \$wsComputopHosted.encryptionType Gibt den Verschlüsselungstyp aus, mit dem `data` verschlüsselt wurde: `"Blowfish"` oder `"AES"` - je nachdem, was in der Computop-Konfiguration eingestellt ist (Standard: Blowfish). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Verschlüsselung: {{= $wsComputopHosted.encryptionType }} ``` ### \$wsComputopHosted.merchantID Gibt die Händler-ID bei Computop aus. Sie wird mit dem Formular übermittelt, damit Computop die Zahlung dem richtigen Händlerkonto zuordnet. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` ### \$wsComputopHosted.payType Gibt die Zahlungsart aus (z. B. Kreditkarte). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Zahlungsart: {{= $wsComputopHosted.payType }} ``` ### \$wsComputopHosted.language Gibt den Sprachcode für die Bezahlseite aus. Damit erscheint die Computop-Seite in der Sprache des Kunden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Sprache: {{= $wsComputopHosted.language }} ``` ### \$wsComputopHosted.template Gibt den Namen des verwendeten Computop-Templates aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Template: {{= $wsComputopHosted.template }} ``` ### \$wsComputopHosted.hideSave Gibt den Wert zur Steuerung der Speichern-Option auf der Computop-Bezahlseite aus. Die Variable enthält den Text `"hideSave"` und ist **nur vorhanden, wenn die Option ausgeblendet werden soll** - in zwei Fällen: * Der Kunde bezahlt mit einer bereits gespeicherten Kreditkarte (siehe [`PCNr`](#wscomputophosted-pcnr-pcnrbrand-pcnryear-pcnrmonth-holder)) - erneutes Speichern ist dann überflüssig. * Das Speichern ist nicht möglich, weil der Kunde nicht eingeloggt ist oder das Speichern von Pseudo-Kreditkartendaten für den Shop nicht aktiviert ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsComputopHosted.hideSave }} {{ /if }} ``` ### \$wsComputopHosted.prefill Enthält den Wert `"on"`, wenn die Speichern-Option auf der Computop-Bezahlseite standardmäßig angehakt sein soll (in der Computop-Konfiguration einstellbar). Nur dann vorhanden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsComputopHosted.prefill }} {{ /if }} ``` ### \$wsComputopHosted.PCNr / PCNrBrand / PCNrYear / PCNrMonth / holder Geben die Daten einer **gespeicherten Pseudo-Kreditkarte** aus, damit der Kunde nicht erneut seine Kartendaten eingeben muss. Die Variablen sind nur vorhanden, wenn alle Voraussetzungen erfüllt sind: * Der Kunde ist eingeloggt, * das Speichern von Pseudo-Kreditkartendaten ist für den Shop aktiviert, * und der Kunde hat im Checkout eine gespeicherte Karte gewählt (siehe [`$wsCheckout.selectedPseudoCC`](/frontend/referenz/module/wscheckout#wscheckout-selectedpseudocc)). `PCNr` (Pseudo-Kartennummer) ist dabei immer gesetzt; die übrigen Variablen erscheinen nur, wenn der jeweilige Wert bei der Karte hinterlegt ist. Ist `PCNr` vorhanden, wird zugleich [`hideSave`](#wscomputophosted-hidesave) gesetzt, da die Karte bereits gespeichert ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsComputopHosted.PCNr }} Gespeicherte Karte: {{= $wsComputopHosted.PCNrBrand }} ({{= $wsComputopHosted.holder }}), gültig bis {{= $wsComputopHosted.PCNrMonth }}/{{= $wsComputopHosted.PCNrYear }} {{ /if }} ``` ### \$wsComputopHosted.freeFields Gibt die freien Checkout-Felder aus, die an Computop übermittelt werden. Übermittelt werden nur die [freien Checkout-Felder](/frontend/referenz/module/wscheckout#wscheckout-freefields), deren ID in der Computop-Zahlungskonfiguration unter `freeFields` eingetragen ist. #### Eigenschaften eines freien Feldes | **Eigenschaft** | **Typ** | **Beschreibung** | | --------------- | ------- | ------------------------------------ | | `id` | string | ID des freien Checkout-Feldes. | | `value` | string | Aktueller Wert des Feldes. | | `type` | string | Feldtyp: `"text"` oder `"checkbox"`. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $field in $wsComputopHosted.freeFields }} {{= $field.id }}: {{= $field.value }} ({{= $field.type }}) {{ /foreach }} ``` ### \$wsComputopHosted.error Gibt eine Fehlermeldung aus, falls bei der Zahlung ein Problem aufgetreten ist. Werten Sie sie nach der Rückkehr auf die Bezahlseite aus, um dem Kunden den Grund zu nennen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsComputopHosted.error }} {{= $wsComputopHosted.error }} {{ /if }} ``` ### \$wsComputopHosted.paymentCanceled Gibt `true` zurück, wenn der Kunde die Zahlung abgebrochen hat. Nutzen Sie es, um nach dem Abbruch zur Zahlungsauswahl zurückzuführen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsComputopHosted.paymentCanceled }} Sie haben die Zahlung abgebrochen. {{ /if }} ``` ### \$wsComputopHosted.paymentFailed Gibt `true` zurück, wenn die Zahlung fehlgeschlagen ist. Im Unterschied zum Abbruch hat der Kunde die Zahlung versucht, sie wurde aber nicht erfolgreich abgeschlossen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsComputopHosted.paymentFailed }} Die Zahlung ist fehlgeschlagen. Bitte versuchen Sie es erneut. {{ /if }} ``` *** ## Methoden Für `$wsComputopHosted` stehen keine Methoden zur Verfügung. *** ## Aktionen Für `$wsComputopHosted` stehen keine Aktionen zur Verfügung. *** ## Beispiele ### Weiterleitung zur Computop-Bezahlseite Dieses Beispiel baut das vollständige Weiterleitungs-Formular: Es zeigt auf `action` und legt die verschlüsselten Daten sowie die Händler-ID als versteckte Felder ab. Beim Absenden gelangt der Kunde zur Computop-Bezahlseite. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
    ``` **Ergebnis** \ Beim Absenden wird der Kunde zur Computop-Bezahlseite weitergeleitet. ### Zahlungsergebnis nach der Rückkehr auswerten Nachdem Computop den Kunden zurückgeleitet hat, prüfen Sie das Ergebnis und zeigen die passende Meldung. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsComputopHosted.paymentCanceled }} Sie haben die Zahlung abgebrochen. {{ elseif $wsComputopHosted.paymentFailed }} Die Zahlung ist fehlgeschlagen. {{ if $wsComputopHosted.error }} Grund: {{= $wsComputopHosted.error }} {{ /if }} {{ else }} Vielen Dank für Ihre Zahlung. {{ /if }} ``` **Ergebnis** \ Je nach Ausgang sieht der Kunde eine Abbruch-, Fehler- oder Erfolgsmeldung. *** ## Weiterführende Links * [Computop Hosted Payments (Konfiguration)](/konfiguration/payment-zahlungsmethoden#2-payment-computophosted-computop-hosted-payments) – richtet die Computop-Schnittstelle ein (Händler-ID, Schlüssel, Zahlungsarten). Voraussetzung, damit das Modul gefüllt ist. * [\$wsCheckout](/frontend/referenz/module/wscheckout) – der Checkout, aus dem heraus zur Computop-Bezahlseite weitergeleitet wird; liefert mit `selectedPseudoCC` die gewählte gespeicherte Karte. # $wsConfig - Konfiguration Source: https://dokumentation.websale.de/frontend/referenz/module/wsconfig Globale Konfigurationsdaten des Shops im Frontend lesen: Länder, Währungen, Zahlungs- und Versandarten, Anreden, Sprachen und weitere Stammdaten. Mit dem `$wsConfig`-Modul lesen Sie die Konfigurationsdaten des Shops im Frontend, beispielsweise die verfügbaren Länder, die Währung, die Zahlungs- und Versandarten sowie die konfigurierten Anreden und Titel. Auf dieser Seite geht es um das Lesen der Konfiguration. Die Konfiguration selbst wird im Admin-Interface bzw. [per Code](/frontend/die-basics/konfiguration-per-code) gepflegt, nicht über dieses Modul. *** ## Grundkonzept `$wsConfig` ist ein reines Lese-Modul. Es spiegelt die im Shop hinterlegte Konfiguration zum Zeitpunkt des Seitenaufbaus wider. Die Werte ändern sich nur, wenn die Konfiguration geändert wird und nicht durch eine Aktion des Kunden. Die Variablen lassen sich wie folgt gruppieren: * **Listen für Formulare** – [`countries`](#wsconfig-countries), [`salutation`](#wsconfig-salutation), [`title`](#wsconfig-title), [`listElements`](#wsconfig-listelements): füllen z. B. Auswahlfelder in Adress- und Anmeldeformularen. * **Checkout-Optionen** – [`payments`](#wsconfig-payments), [`shippingMethods`](#wsconfig-shippingmethods): die verfügbaren Zahlungs- und Versandarten. * **Anzeige** – [`currency`](#wsconfig-currency): Währungssymbol und -codes. * **Verhalten und Sicherheit** – [`passwordChecks`](#wsconfig-passwordchecks), [`passwordReset`](#wsconfig-passwordreset), [`directOrder`](#wsconfig-directorder), [`redirects`](#wsconfig-redirects), [`emails`](#wsconfig-emails). * **Werbemittelkennzeichen** – [`inserts`](#wsconfig-inserts): Einstellungen der [Werbemittelkennzeichnung](/frontend/funktionsubersicht/werbemittelkennzeichnung) (aktiv, Trennzeichen, Position, Standardcode). ### Währung formatieren Der `currency`-Filter (`| currency`) gibt einen Betrag bereits **mit** Währungssymbol aus (z. B. `1.500,00 €`). Verwenden Sie [`currency.symbol`](#wsconfig-currency) deshalb **nicht** zusätzlich zu `| currency` – sonst erscheint das Symbol doppelt. `currency.symbol` brauchen Sie nur, wenn Sie einen Wert selbst formatieren oder das Symbol einzeln anzeigen. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsConfig` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsConfig | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "countries": [ { "isoAlpha2": "...", "isoAlpha3": "...", "isoNum": "...", "name": "..." } ], "currency": { "symbol": "...", "isoCode": "...", "isoNum": "..." }, "directOrder": { "initialNumber": 0, "maximalNumber": 0, "refreshedNumber": 0, "itemNumberFields": [...] }, "emails": [...], "inserts": { "enabled": false, "separator": "...", "position": "...", "defaultInsertCode": "..." }, "listElements": { "bill": { }, "delivery": { }, "": { } }, "passwordChecks": { "maxLength": { "len": 0 }, "minLength": { "len": 0 } }, "passwordReset": { "checkLoginID": false, "checkOldPassword": false }, "payments": [ { "id": "...", "name": "...", "description": "...", "image": "..." } ], "redirects": [...], "salutation": { "codeList": [ { "code": "...", "text": "..." } ] }, "shippingMethods": [ { "id": "...", "name": "...", "description": "...", "image": "...", "link": "...", "type": "...", "group": "..." } ], "shippingMethodGroups": [ { "id": "...", "name": "...", "description": "...", "image": "...", "link": "..." } ], "title": { "codeList": [ { "code": "...", "text": "..." } ] } } ``` **Variablen in der Übersicht** | **Variable** | **Typ** | **Beschreibung** | | ---------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------- | | `countries` | array | Konfigurierte Länder (Struktur siehe unten). | | `currency` | map | Währungsdaten (Symbol, Codes). | | `salutation` | map | Konfigurierte Anreden (unter `codeList`). | | `title` | map | Konfigurierte Titel (unter `codeList`). | | `payments` | array | Konfigurierte Zahlungsarten (Struktur siehe unten). | | `shippingMethods` | array | Konfigurierte Versandarten (Struktur siehe unten). | | `shippingMethodGroups` | array | Gruppen von Versandarten (Struktur siehe unten). | | `listElements` | map | Konfigurierte Adresslisten für Formulare, gruppiert nach `bill` und `delivery`; Listen ohne `addressType` liegen direkt darunter. | | `passwordChecks` | map | Passwort-Längenregeln. | | `passwordReset` | map | Einstellungen zum Passwort-Reset. | | `directOrder` | map | Einstellungen der Direktbestellung. | | `emails` | array | E-Mail-Konfigurationen. | | `redirects` | array | Weiterleitungs-Konfigurationen. | | `inserts` | map | Einstellungen der Werbemittelkennzeichnung (aktiv, Trennzeichen, Position, Standardcode). | | `b2bSubAccounts` | map | B2B-Unterkonten-Einstellungen (`subAccountsEnabled`, `adminCanEditMemberAddresses`). | *** ## Templates Die Konfigurationsdaten können auf jeder Seite verwendet werden. Typische Einsatzgebiete: Formulare (Länder-, Anredeauswahl), Checkout (Zahlungs- und Versandarten) und Preisanzeige (Währung). *** ## Variablen ### \$wsConfig.countries Gibt die konfigurierten Länder aus. Nutzen Sie die Liste, um beispielsweise ein Länder-Auswahlfeld in einem Adressformular zu füllen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $country in $wsConfig.countries }} {{= $country.name }} ({{= $country.isoAlpha2 }}) {{ /foreach }} ``` #### Eigenschaften eines Landes | **Eigenschaft** | **Typ** | **Beschreibung** | | --------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `nodeId` | string | ID des Konfigurationsknotens dieses Landes, als zweiter Parameter für [`$wsOptions.get(name, nodeId)`](/frontend/referenz/module/ws-options-template-optionen). | | `name` | string | Name des Landes. | | `isoAlpha2` | string | ISO-2-Ländercode (z. B. `"DE"`, `"AT"`). | | `isoAlpha3` | string | ISO-3-Ländercode (z. B. `"DEU"`, `"AUT"`). | | `isoNum` | string | ISO-Zifferncode (z. B. `"276"`, `"040"`). | ### \$wsConfig.currency Gibt die Währungsdaten aus. Für die Anzeige eines Betrags verwenden Sie in der Regel den `currency`-Filter (siehe [Währung formatieren](#währung-formatieren)). #### Eigenschaften von `$wsConfig.currency` | **Eigenschaft** | **Typ** | **Beschreibung** | | --------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `nodeId` | string | ID des Konfigurationsknotens der Währungs-Konfiguration, als zweiter Parameter für [`$wsOptions.get(name, nodeId)`](/frontend/referenz/module/ws-options-template-optionen). | | `symbol` | string | Währungssymbol (z. B. `€`). | | `isoCode` | string | ISO-Währungscode (z. B. `"EUR"`). | | `isoNum` | string | ISO-Zifferncode der Währung (z. B. `"978"`). | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Währung: {{= $wsConfig.currency.isoCode }} ({{= $wsConfig.currency.symbol }}) ``` ### \$wsConfig.salutation Gibt die konfigurierten Anreden aus. Die eigentliche Liste liegt unter `salutation.codeList`. Nutzen Sie sie beispielsweise, um ein Anrede-Auswahlfeld zu füllen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $salutation in $wsConfig.salutation.codeList }} {{= $salutation.text }} {{ /foreach }} ``` #### Eigenschaften eines Eintrags in `salutation.codeList` | **Eigenschaft** | **Typ** | **Beschreibung** | | --------------- | ------- | --------------------------------------------------------------- | | `code` | string | Anrede-Code (z. B. `"1"`, `"2"`). | | `text` | string | Anzeigetext (z. B. `"Herr"`, `"Frau"`, `"Familie"`, `"Firma"`). | ### \$wsConfig.title Gibt die konfigurierten Titel aus. Die Liste liegt unter `title.codeList`. Aufbau analog zu `salutation`. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $title in $wsConfig.title.codeList }} {{= $title.text }} {{ /foreach }} ``` #### Eigenschaften eines Eintrags in `title.codeList` | **Eigenschaft** | **Typ** | **Beschreibung** | | --------------- | ------- | ------------------------------------------------------- | | `code` | string | Titel-Code (z. B. `"1"`). | | `text` | string | Anzeigetext (z. B. `"Dr."`, `"Prof."`; kann leer sein). | ### \$wsConfig.payments Gibt die konfigurierten Zahlungsarten aus. Nutzen Sie sie, um die verfügbaren Zahlungsarten anzuzeigen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $payment in $wsConfig.payments }} {{= $payment.name }}: {{= $payment.description }} {{ /foreach }} ``` #### Eigenschaften einer Zahlungsart | **Eigenschaft** | **Typ** | **Beschreibung** | | ----------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | ID der Zahlungsart (z. B. `"paypalCheckout"`, `"stripe"`). | | `nodeId` | string | ID des Konfigurationsknotens dieser Zahlungsart, als zweiter Parameter für [`$wsOptions.get(name, nodeId)`](/frontend/referenz/module/ws-options-template-optionen). Nicht zu verwechseln mit `id`. | | `name` | string | Name der Zahlungsart. | | `description` | string | Beschreibung der Zahlungsart. | | `longDescription` | string | Längere Beschreibung der Zahlungsart (lange Variante von `description`), gepflegt unter [`payment.payment`](/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen). | | `image` | string | Bild-URL der Zahlungsart. | | `discount` | float | Rabatt der Zahlungsart. | | `provider` | string | Anbieter der Zahlungsart. | | `type` | string | Typ der Zahlungsart. | | `labels` | array | Labels der Zahlungsart. | | `displayInfo` | array | Zusätzliche Anzeigeinformationen (siehe Hinweis). | `displayInfo` ist nur befüllt, wenn für die Zahlungsart der Parameter [displayPaymentTypes](/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen) konfiguriert wurde. Jeder Eintrag enthält `name`, `description` und `image`. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $payment in $wsConfig.payments }} {{ foreach $info in $payment.displayInfo }} {{= $info.name }} – {{= $info.description }} {{ /foreach }} {{ /foreach }} ``` ### \$wsConfig.shippingMethods Gibt die konfigurierten Versandarten aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $shipping in $wsConfig.shippingMethods }} {{= $shipping.name }} ({{= $shipping.type }}) {{ /foreach }} ``` #### Eigenschaften einer Versandart | **Eigenschaft** | **Typ** | **Beschreibung** | | --------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | ID der Versandart (z. B. `"dhl"`). | | `nodeId` | string | ID des Konfigurationsknotens dieser Versandart, als zweiter Parameter für [`$wsOptions.get(name, nodeId)`](/frontend/referenz/module/ws-options-template-optionen). | | `name` | string | Name der Versandart. | | `description` | string | Beschreibung der Versandart. | | `image` | string | Bild-URL der Versandart. | | `link` | string | Link zur Versandart (z. B. Tracking-Seite). | | `type` | string | Typ der Versandart (z. B. `"standard"`). | | `group` | string | Zugeordnete Versandart-Gruppe (kann `null` sein). | Die **Versandkosten** sind nicht Teil der Konfiguration. Sie hängen vom Warenkorb ab und werden über [`$wsCheckout.getShippingCost(shippingMethodId)`](/frontend/referenz/module/wscheckout#wscheckout-getshippingcost) ermittelt. ### \$wsConfig.shippingMethodGroups Gibt die konfigurierten Versandarten-Gruppen aus. Über eine Gruppe lassen sich mehrere Versandarten zusammenfassen (z. B. nach Anbieter oder Lieferart). Welche Gruppe einer Versandart zugeordnet ist, steht im Feld `group` der jeweiligen Versandart (siehe [Eigenschaften einer Versandart](#eigenschaften-einer-versandart)). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $group in $wsConfig.shippingMethodGroups }} {{= $group.name }}: {{= $group.description }} {{ /foreach }} ``` #### Eigenschaften einer Gruppe | **Eigenschaft** | **Typ** | **Beschreibung** | | --------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | ID der Gruppen-Konfiguration. | | `nodeId` | string | ID des Konfigurationsknotens dieser Gruppe, als zweiter Parameter für [`$wsOptions.get(name, nodeId)`](/frontend/referenz/module/ws-options-template-optionen). | | `name` | string | Name der Gruppe. | | `description` | string | Beschreibung der Gruppe. | | `image` | string | Bild-URL (Link) der Gruppe. | | `link` | string | Link der Gruppe. | ### \$wsConfig.listElements Gibt die konfigurierten [Adresslisten](/konfiguration/general-allgemeine-shopeinstellungen#general-addresslistelements-adresslisten) für Formulare aus, beispielsweise Privat / Firma / Packstation. Nutzen Sie sie, um Auswahlfelder in Adressformularen zu füllen. Jede Liste ist unter ihrem konfigurierten `name` erreichbar. Unter welchem Pfad sie liegt, bestimmt der Parameter `addressType` der jeweiligen Liste: | **`addressType` in der Konfiguration** | **Pfad im Template** | | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | | `"bill"` | `$wsConfig.listElements.bill.` | | `"delivery"` | `$wsConfig.listElements.delivery.` | | `"both"` | `$wsConfig.listElements.bill.` **und** `$wsConfig.listElements.delivery.` (dieselbe Liste, unter beiden Pfaden) | | nicht gesetzt | `$wsConfig.listElements.` (direkt, **nicht** unter `bill`/`delivery`) | Der Schlüssel ist der `name` der Liste, nicht deren `dataId`. Sind beide unterschiedlich gepflegt, ist die Liste im Template ausschließlich über `name` erreichbar. Die `dataId` wird dagegen in der [Feldvalidierung](/konfiguration/validierungs-und-prufservices#addresscheck-allowedselection-auswahl-listenelement) referenziert. #### Eigenschaften eines Eintrags in `listElements` | **Eigenschaft** | **Typ** | **Beschreibung** | | ---------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `nodeId` | string | ID des Konfigurationsknotens dieser Liste, als zweiter Parameter für [`$wsOptions.get(name, nodeId)`](/frontend/referenz/module/ws-options-template-optionen). | | `defaultValue` | string | Vorausgewählter Wert (z. B. `"1"`). Leer, wenn in der Konfiguration kein Standardwert gesetzt ist. | | `values` | array | Auswählbare Optionen in Anzeige-Reihenfolge, je `{ name, value }`. | | `values[].name` | string | Anzeigename der Option (z. B. `"Privat"`). | | `values[].value` | string | Technischer Wert der Option (z. B. `"1"`). | `values` enthält nur Optionen mit zulässigen Werten. Optionen, deren Wert Sonderzeichen enthält oder deren Name leer ist, werden beim Seitenaufbau übersprungen und fehlen hier ohne Fehlermeldung – siehe [`general.addressListElements`](/konfiguration/general-allgemeine-shopeinstellungen#general-addresslistelements-adresslisten). Wenn eine erwartete Option im Formular fehlt, prüfen Sie zuerst deren `value`. **Beispiel,** das die Rechnungsadress-Liste `billAddressType` als Auswahlfeld ausgibt. Vorausgewählt wird der bereits gespeicherte Wert der bearbeiteten Adresse (`$myAddress`), andernfalls der konfigurierte `defaultValue`. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myList = $wsConfig.listElements.bill.billAddressType }} ``` **Ergebnis**
    Ein Auswahlfeld mit allen konfigurierten Optionen der Liste. Beim Bearbeiten einer bestehenden Adresse ist der gespeicherte Wert vorausgewählt, beim Anlegen einer neuen Adresse der Standardwert. `$myAddress` steht im Beispiel für die Adresse, die im Formular bearbeitet wird – etwa eine Adresse aus [`$wsAccount.addresses`](/frontend/referenz/module/wsAccount#wsaccount-addresses) oder eine per [`$wsAccount.loadAddress()`](/frontend/referenz/module/wsAccount#wsaccount-loadaddress) geladene Adresse. Beim Anlegen einer neuen Adresse ist die Variable leer und der `else`-Zweig greift. Sollen alle Listen eines Adresstyps dynamisch ausgegeben werden, iterieren Sie über die Map. Verwenden Sie dabei je Liste einen eigenen Feldnamen, damit die Werte beim Absenden unterscheidbar bleiben. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $myListName, $myList in $wsConfig.listElements.bill }} {{ /foreach }} ``` ### \$wsConfig.passwordChecks Gibt die Längenregeln für Passwörter aus. Nutzen Sie sie beispielsweise, um in einem Registrierungs- oder Passwort-Formular die erlaubte Länge anzuzeigen oder clientseitig zu prüfen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Passwortlänge: {{= $wsConfig.passwordChecks.minLength.len }} bis {{= $wsConfig.passwordChecks.maxLength.len }} Zeichen ``` #### Eigenschaften von `$wsConfig.passwordChecks` | **Eigenschaft** | **Typ** | **Beschreibung** | | --------------- | ------- | ----------------------- | | `minLength.len` | int | Minimale Passwortlänge. | | `maxLength.len` | int | Maximale Passwortlänge. | ### \$wsConfig.passwordReset Gibt die Einstellungen zum Passwort-Reset aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsConfig.passwordReset.checkOldPassword }} {{ /if }} ``` #### Eigenschaften von `$wsConfig.passwordReset` | **Eigenschaft** | **Typ** | **Beschreibung** | | ------------------ | ------- | ----------------------------------------------------------------------------------------------------------- | | `checkLoginID` | bool | Ob die Login-ID beim Reset geprüft wird. | | `checkOldPassword` | bool | Ob zur Änderung des Passworts zusätzlich das bisherige Passwort abgefragt und auf Korrektheit geprüft wird. | ### \$wsConfig.directOrder Gibt die Einstellungen der Direktbestellung aus (z. B. wie viele Eingabezeilen angezeigt werden). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Start-Zeilen: {{= $wsConfig.directOrder.initialNumber }} Max. Zeilen: {{= $wsConfig.directOrder.maximalNumber }} ``` #### Eigenschaften von `$wsConfig.directOrder` | **Eigenschaft** | **Typ** | **Beschreibung** | | ------------------ | ------- | ------------------------------------------ | | `initialNumber` | int | Anzahl der initial angezeigten Zeilen. | | `maximalNumber` | int | Maximale Anzahl von Zeilen. | | `refreshedNumber` | int | Anzahl neu geladener Zeilen. | | `itemNumberFields` | array | Artikelnummer-Felder der Direktbestellung. | ### \$wsConfig.inserts Gibt die Einstellungen der [Werbemittelkennzeichnung](/frontend/funktionsubersicht/werbemittelkennzeichnung) aus. Nutzen Sie insbesondere `enabled`, um Ausgaben rund um das Werbemittelkennzeichen nur dann anzuzeigen, wenn die Funktion im Shop aktiv ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsConfig.inserts.enabled }} {{ /if }} ``` #### Eigenschaften von `$wsConfig.inserts` | **Eigenschaft** | **Typ** | **Beschreibung** | | ------------------- | ------- | ----------------------------------------------------------------------------------------------------------- | | `enabled` | bool | Ob die Werbemittelkennzeichnung im Shop aktiv ist. Nur dann werden Codes erfasst, aufgelöst und ausgegeben. | | `separator` | string | Trennzeichen zwischen Produktnummer und Code (z. B. `-`). | | `position` | string | Position des Codes relativ zur Produktnummer: `before` (davor) oder `after` (dahinter). | | `defaultInsertCode` | string | Standardcode, der greift, wenn kein oder ein ungültiger Code erfasst wurde. Kann leer sein. | ### \$wsConfig.emails Gibt die E-Mail-Konfigurationen aus. Jeder Eintrag enthält zusätzlich das Feld `nodeId`, die ID des Konfigurationsknotens, nutzbar als zweiter Parameter für [`$wsOptions.get(name, nodeId)`](/frontend/referenz/module/ws-options-template-optionen) (siehe [Optionen](/frontend/referenz/optionen)). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsConfig.emails | json }} ``` ### \$wsConfig.redirects Gibt die Weiterleitungs-Konfigurationen aus. Jeder Eintrag enthält zusätzlich das Feld `nodeId`, die ID des Konfigurationsknotens, nutzbar als zweiter Parameter für [`$wsOptions.get(name, nodeId)`](/frontend/referenz/module/ws-options-template-optionen) (siehe [Optionen](/frontend/referenz/optionen)). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsConfig.redirects | json }} ``` *** ## Methoden Für `$wsConfig` stehen keine Methoden zur Verfügung. *** ## Aktionen Für `$wsConfig` stehen keine Aktionen zur Verfügung. *** ## Beispiele ### Länder-Auswahlfeld ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` **Ergebnis**
    Ein Auswahlfeld mit allen konfigurierten Ländern. Der Wert ist der ISO-2-Code. ### Anrede-Auswahlfeld ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` **Ergebnis**
    Ein Auswahlfeld mit allen konfigurierten Anreden. ### Zahlungsarten auflisten ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $payment in $wsConfig.payments }}

    {{= $payment.name }} – {{= $payment.description }}

    {{ /foreach }} ``` **Ergebnis**
    Alle konfigurierten Zahlungsarten mit Name und Beschreibung. ### Währung korrekt anzeigen ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Zwischensumme: {{= $wsBasket.totalGross | currency }} ``` **Ergebnis**
    Der Betrag wird mit Währungssymbol ausgegeben (z. B. `1.500,00 €`). *** ## Weiterführende Links * [Konfiguration](/konfiguration) – wo die hier gelesenen Werte gepflegt werden. * [Konfiguration per Code](/frontend/die-basics/konfiguration-per-code) – Konfiguration direkt im Template. * [\$wsCheckout](/frontend/referenz/module/wscheckout) – ermittelt u. a. die Versandkosten je Versandart. * [Werbemittelkennzeichen](/frontend/funktionsubersicht/werbemittelkennzeichnung) – Übersicht der Werbemittelkennzeichnung, deren Einstellungen `$wsConfig.inserts` liefert. * [ISO-3166-1-Kodierliste](https://de.wikipedia.org/wiki/ISO-3166-1-Kodierliste) – Bedeutung der Ländercodes. # $wsConsent - Cookies & Services Source: https://dokumentation.websale.de/frontend/referenz/module/wsconsent Cookie- und Service-Einwilligung des Kunden im Frontend auswerten, um Tracking, Drittanbieter-Skripte und eingebettete Inhalte rechtskonform zu steuern. Mit dem `$wsConsent`-Modul lesen Sie die Einwilligung des Kunden zu Cookies und Services und steuern damit, welche Inhalte und externen Skripte geladen werden. Damit können Sie beispielsweise einen Tracking- oder Marketing-Service erst dann einbinden, wenn der Kunde ihm zugestimmt hat. Auf dieser Seite geht es um das Lesen des Einwilligungsstatus. Das Setzen der Einwilligung (Zustimmen, Ablehnen, Auswahl speichern) erfolgt über Aktionen und ist separat unter [Aktionen → Consent](/frontend/referenz/aktionen/consent) dokumentiert. Die zugehörigen Cookies selbst behandelt das Modul [\$wsCookies](/frontend/referenz/module/ws-cookie-browser-cookie). *** ## Grundkonzept Die Einwilligung ist zweistufig organisiert: Gruppen (z. B. „Statistik“, „Marketing“) bündeln einzelne Services (z. B. „Google Analytics“). Der Kunde kann entweder allen zustimmen („Alle erlauben") oder eine Auswahl pro Gruppe/Service treffen. Jeder Eintrag trägt ein „allowed“-Flag, das die Entscheidung widerspiegelt. `$wsConsent` stellt diesen Status auf folgenden Wegen bereit: * **Gesamtstatus** – [`alreadySet`](#wsconsent-alreadyset) (hat der Kunde überhaupt schon entschieden?) und [`allAllowed`](#wsconsent-allallowed) (hat er allem zugestimmt?). Damit steuern Sie, ob der Consent-Layer überhaupt angezeigt werden muss. * **Strukturierte Liste** – [`groups`](#wsconsent-groups) mit ihren `services`, um einen Consent-Layer aufzubauen. * **Gezielte Prüfung** – [`checkAllowed(serviceName)`](#wsconsent-checkallowed), um vor dem Laden eines bestimmten Skripts die Zustimmung zu prüfen. Das ist der empfohlene Weg zum Einbinden externer Skripte. ### Einwilligung entscheidet, ob das Skript überhaupt geladen wird Template-Code läuft beim Seitenaufbau. Wenn Sie ein Skript mit `{{ if $wsConsent.checkAllowed(...) }}` umschließen, wird das Skript bei fehlender Zustimmung gar nicht erst in die Seite geschrieben, nicht nur ausgeblendet. So stellen Sie sicher, dass ein abgelehnter Service auch wirklich nicht lädt. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsConsent` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsConsent | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "alreadySet": false, "allAllowed": false, "groups": [ { "name": "...", "label": "...", "description": "...", "allowed": false, "services": [ { "name": "...", "label": "...", "description": "...", "allowed": false } ] } ], "services": [ { "name": "...", "label": "...", "description": "...", "allowed": false } ], "checkAllowed": "ƒ()" } ``` Anmerkung: `"ƒ()"` kennzeichnet eine Funktion. **Variablen in der Übersicht** | **Variable** | **Typ** | **Beschreibung** | | ------------ | ------- | ---------------------------------------------------- | | `alreadySet` | bool | Ob der Kunde bereits eine Einwilligung gesetzt hat. | | `allAllowed` | bool | Ob der Kunde allen Cookies/Services zugestimmt hat. | | `groups` | array | Konfigurierte Gruppen, jeweils mit ihren `services`. | | `services` | array | Flache Liste aller konfigurierten Services. | **Eigenschaften eines Eintrags** (gilt für `groups[]` wie für `services[]`) | **Eigenschaft** | **Typ** | **Beschreibung** | | --------------- | ------- | ---------------------------------------------- | | `name` | string | Technischer Name (für `checkAllowed()`). | | `label` | string | Für den Kunden sichtbare Bezeichnung. | | `description` | string | Beschreibung. | | `allowed` | bool | Ob der Eintrag erlaubt (akzeptiert) ist. | | `services` | array | Nur bei `groups[]`: die zugeordneten Services. | **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ---------------- | ---------------- | -------------------------------------------------- | | `checkAllowed()` | bool | Prüft, ob ein bestimmter Service akzeptiert wurde. | *** ## Templates Der Consent-Layer kann global aufgerufen werden und wird aus dem Template `consent.htm` geladen. *** ## Variablen ### \$wsConsent.alreadySet Gibt aus, ob der Kunde bereits eine Cookie-/Service-Einwilligung gesetzt hat. Nutzen Sie es beispielsweise, um den Consent-Layer nur dann anzuzeigen, wenn noch keine Entscheidung vorliegt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if not $wsConsent.alreadySet }} {{ /if }} ``` ### \$wsConsent.allAllowed Gibt aus, ob der Kunde allen Services zugestimmt hat (Schaltfläche „Alle erlauben"). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsConsent.allAllowed }} {{ /if }} ``` ### \$wsConsent.groups Gibt die konfigurierten Gruppen aus. Jede Gruppe trägt die [Eigenschaften eines Eintrags](#modulübersicht) und enthält unter `services` die zugeordneten Services. Nutzen Sie die Gruppen, um einen strukturierten Consent-Layer aufzubauen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $group in $wsConsent.groups }} {{= $group.label }} {{ foreach $service in $group.services }} - {{= $service.label }} {{ /foreach }} {{ /foreach }} ``` ### \$wsConsent.services Gibt alle konfigurierten Services als Liste aus, unabhängig von der Gruppenzuordnung. Die Einträge tragen die [Eigenschaften eines Eintrags](#modulübersicht). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $service in $wsConsent.services }} {{= $service.label }}: {{= $service.allowed }} {{ /foreach }} ``` *** ## Methoden ### \$wsConsent.checkAllowed() Prüft, ob ein bestimmter Service vom Kunden akzeptiert wurde. Dies ist der empfohlene Weg, um vor dem Laden eines externen Skripts die Zustimmung zu prüfen, da das Skript bei fehlender Zustimmung gar nicht erst gerendert wird. **Signatur**\ `$wsConsent.checkAllowed(serviceName)` **Rückgabe**\ `bool` – `true`, wenn der Service akzeptiert wurde, sonst `false`. | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ------------- | ------- | ----------- | --------------------------------------------------------------- | | `serviceName` | string | ja | Technischer Name des Services (das `name`-Feld eines Eintrags). | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsConsent.checkAllowed("googleAnalytics") }} {{ /if }} ``` *** ## Aktionen Aktionen zu diesem Modul (Einwilligung setzen, ändern, speichern) sind separat dokumentiert: [Aktionen → Consent](/frontend/referenz/aktionen/consent). *** ## Beispiele ### Externes Skript einwilligungsabhängig laden Bindet ein Skript nur ein, wenn der zugehörige Service akzeptiert wurde. Bei fehlender Zustimmung wird das Skript nicht in die Seite geschrieben. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsConsent.checkAllowed("googleAnalytics") }} {{ /if }} ``` **Ergebnis** \ Das Tracking-Skript erscheint nur im Quelltext, wenn der Kunde „Google Analytics" akzeptiert hat. ### Consent-Layer aus Gruppen und Services aufbauen Durchläuft die Gruppen und je Gruppe ihre Services, was die typische Struktur eines Consent-Layers widerspiegelt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $group in $wsConsent.groups }}
    {{= $group.label }}

    {{= $group.description }}

    {{ foreach $service in $group.services }} {{ /foreach }}
    {{ /foreach }} ``` **Ergebnis** \ Pro Gruppe ein Block mit den enthaltenen Services; bereits akzeptierte Services sind angehakt. ### Inhalt nur bei Zustimmung anzeigen Zeigt einen einwilligungspflichtigen Inhalt (z. B. ein eingebettetes Video) nur an, wenn der Service akzeptiert wurde, ansonsten einen Hinweis. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsConsent.checkAllowed("youtube") }} {{ else }} Um diese Inhalte zu sehen, akzeptieren Sie bitte den Service „Youtube Videos". {{ /if }} ``` **Ergebnis** \ Bei Zustimmung erscheint der Inhalt, sonst der Hinweis. *** ## Weiterführende Links * [Aktionen → Consent](/frontend/referenz/aktionen/consent) – die Einwilligung setzen und speichern (dieses Modul liest sie nur). * [\$wsCookies](/frontend/referenz/module/ws-cookie-browser-cookie) – die durch die Einwilligung gesteuerten Cookies. # $wsDirectOrder - Direktbestellung Source: https://dokumentation.websale.de/frontend/referenz/module/wsdirectorder Zustand einer Direktbestellung (Scan & Order, Bestellschein) im Frontend lesen: Eingabezeilen, erfasste Positionen und Validität der Eingaben. Mit dem `$wsDirectOrder`-Modul lesen Sie den Zustand einer Direktbestellung. Bei der Direktbestellung legt der Kunde Produkte durch Eingabe ihrer Artikelnummern direkt in den Warenkorb, ohne sie einzeln im Shop zu suchen. Das Modul liefert die aktuelle Anzahl der Eingabezeilen und die bisher erfassten Positionen samt Gültigkeit. Auf dieser Seite geht es um das Lesen des Direktbestell-Zustands. Das Hinzufügen und Löschen von Positionen erfolgt über die Aktionen `DirectOrderAdd` / `DirectOrderDelete`. *** ## Grundkonzept Der Bestellschein ist ein Formular mit mehreren Eingabezeilen. In jede Zeile gibt der Kunde eine Artikelnummer (und eine Menge) ein. Beim Absenden prüft die Aktion `DirectOrderAdd`, ob die Nummer existiert, und legt das Produkt in den Warenkorb. `$wsDirectOrder` stellt dabei den aktuellen Zustand bereit: * [`currentLines`](#wsdirectorder-currentlines) – wie viele Eingabezeilen aktuell angezeigt werden. Der Wert stammt aus der Konfiguration ([`$wsConfig.directOrder`](/frontend/referenz/module/wsconfig#wsconfig-directorder): `initialNumber` bis `maximalNumber`). * [`items`](#wsdirectorder-items) – die bereits erfassten Positionen, je mit `id`, `quantity` und `valid`. ### Gültigkeit Das Feld [`valid`](#wsdirectorder-items) einer Position zeigt an, ob die eingegebene Artikelnummer im Shop existiert und bestellbar ist. Werten Sie es aus, um dem Kunden eine ungültige Eingabe direkt zurückzumelden. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsDirectOrder` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsDirectOrder | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "currentLines": 5, "items": [ { "id": "123-45678", "quantity": 1, "valid": true }, { "id": "910-111213", "quantity": 1, "valid": false } ] } ``` **Variablen in der Übersicht** | **Variable** | **Typ** | **Beschreibung** | | -------------- | ------- | -------------------------------------------------- | | `currentLines` | int | Aktuelle Anzahl der angezeigten Eingabezeilen. | | `items` | array | Erfasste Bestellpositionen (Struktur siehe unten). | **Eigenschaften einer Bestellposition (`items[]`)** | **Eigenschaft** | **Typ** | **Beschreibung** | | --------------- | ------- | ------------------------------------------------------------ | | `id` | string | Eingegebene Artikelnummer. | | `quantity` | int | Eingegebene Menge. | | `valid` | bool | `true`, wenn die Artikelnummer existiert und bestellbar ist. | *** ## Templates Der Bestellschein liegt im Standard im Template `module/directOrder.htm`. Verlinken Sie ihn z. B. im Footer (siehe [Beispiel](#seite-im-footer-verlinken)). *** ## Variablen ### \$wsDirectOrder.currentLines Gibt die aktuelle Anzahl der angezeigten Eingabezeilen aus. Der Wert wird über [`$wsConfig.directOrder`](/frontend/referenz/module/wsconfig#wsconfig-directorder) konfiguriert (`initialNumber` als Start, `maximalNumber` als Obergrenze). Nutzen Sie ihn beispielsweise, um genau so viele Zeilen zu erzeugen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Aktuelle Zeilen: {{= $wsDirectOrder.currentLines }} ``` ### \$wsDirectOrder.items Gibt die erfassten Bestellpositionen aus. Über den Zeilenindex greifen Sie auf eine bestimmte Position zu (`items[$index]`). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $item in $wsDirectOrder.items }} {{= $item.id }} – Menge: {{= $item.quantity }} – gültig: {{= $item.valid }} {{ /foreach }} ``` #### Eigenschaften einer Bestellposition | **Eigenschaft** | **Typ** | **Beschreibung** | | --------------- | ------- | ------------------------------------------------------------ | | `id` | string | Eingegebene Artikelnummer. | | `quantity` | int | Eingegebene Menge. | | `valid` | bool | `true`, wenn die Artikelnummer existiert und bestellbar ist. | *** ## Methoden Für `$wsDirectOrder` stehen keine Methoden zur Verfügung. *** ## Aktionen `$wsDirectOrder` selbst stellt keine Aktionen bereit. Das Hinzufügen und Löschen von Positionen erfolgt über die [Aktionen](/frontend/referenz/aktionen/directorder). *** ## Beispiele ### Bestellschein-Template Dieses Beispiel erzeugt für jede konfigurierte Zeile (`currentLines`) eine Eingabereihe. `range(0, currentLines - 1)` liefert die Indizes `0` bis `currentLines - 1`. Pro Zeile werden die Aktionen `DirectOrderAdd` und `DirectOrderDelete` mit dem Zeilenindex als `tag` erzeugt, damit Eingaben und Fehler der richtigen Zeile zugeordnet werden. Der Filter `ifNull('')` setzt einen leeren Wert, falls die Zeile noch nicht erfasst wurde. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ extends "layouts/layout.htm" }} {{ block content_main }}

    Direktbestellung

    {{ foreach $cProduct in range(0, $wsDirectOrder.currentLines - 1) }} {{ var $cActionDirectOrderAdd = $wsActions.create("DirectOrderAdd", tag=string($cProduct)) }} {{ var $cActionDirectOrderDelete = $wsActions.create("DirectOrderDelete", tag=string($cProduct)) }} {{ /foreach }}

    Bitte Artikelnummer eingeben

    {{ foreach $field in $wsConfig.directOrder.itemNumberFields }} {{ if $field.type == "field" }} {{ elseif $field.type == "separator" }} {{= $field.sign }} {{ /if }} {{ /foreach }}
    {{ /block }} ``` **Ergebnis** \ Ein Bestellschein mit so vielen Eingabereihen, wie `currentLines` vorgibt. Bereits erfasste Zeilen haben ihre Artikelnummer und Menge vorbelegt. ### Fehlermeldungen anzeigen Die Aktion `DirectOrderAdd` meldet Fehler feldbezogen über `errorsByField`. Dieses Beispiel zeigt die Fehler zur Artikelnummer (`id`) und zur Menge (`quantity`) je Zeile. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $cProduct in range(0, $wsDirectOrder.currentLines - 1) }} {{ var $cActionDirectOrderAdd = $wsActions.create("DirectOrderAdd", tag=string($cProduct)) }} {{ if $cActionDirectOrderAdd.errorsByField.id }}
    {{ foreach $err in $cActionDirectOrderAdd.errorsByField.id }} {{ if $err.text }}{{= $err.text }}{{ else }}{{= $err.code }}{{ /if }} {{ /foreach }}
    {{ /if }} {{ if $cActionDirectOrderAdd.errorsByField.quantity }}
    {{ foreach $err in $cActionDirectOrderAdd.errorsByField.quantity }} {{ if $err.text }}{{= $err.text }}{{ else }}{{= $err.code }}{{ /if }} {{ /foreach }}
    {{ /if }} {{ /foreach }} ``` **Ergebnis** \ Bei fehlerhafter Eingabe (z. B. ungültige Artikelnummer oder Menge) erscheint die zugehörige Meldung in der betreffenden Zeile. ### Seite im Footer verlinken Den Link zur Direktbestellung erzeugen Sie mit `viewUrl()`. Den Pfad zum Template als Argument übergeben. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Direktbestellung ``` **Ergebnis** \ Ein Link, der zur Direktbestell-Seite führt. *** ## Weiterführende Links * [\$wsActions](/frontend/referenz/module/wsactions) – stellt die Aktionen `DirectOrderAdd` / `DirectOrderDelete` und die Fehlerstruktur `errorsByField` bereit. * [\$wsConfig.directOrder](/frontend/referenz/module/wsconfig#wsconfig-directorder) – konfiguriert Zeilenanzahl und zusätzliche Artikelnummer-Felder. * [Online-Bestellschein](/frontend/praxisbeispiele/bestellablauf-bestellfunktionen/online-bestellschein) – ausführliches Praxisbeispiel. * [checkout - Bestellablauf](/konfiguration/checkout-bestellablauf) – Konfiguration des Bestellablaufs. # $wsEmails - E-Mails Source: https://dokumentation.websale.de/frontend/referenz/module/wsemails Vorkonfigurierte Shop-E-Mails (Bestellbestätigung, Erinnerungen, Benachrichtigungen) aus dem Frontend gezielt und ereignisgesteuert auslösen. Mit dem `$wsEmails`-Modul lösen Sie den Versand vorkonfigurierter E-Mails aus. Die E-Mails selbst werden in der Shop-Konfiguration unter `messages` definiert. Das Modul stößt den Versand einer dieser E-Mails über ihre ID an. Auf dieser Seite geht es um das Auslösen des Versands. Inhalt, Empfänger und Layout der E-Mail werden in der `messages`-Konfiguration festgelegt, nicht hier. *** ## Grundkonzept `$wsEmails` kennt genau eine Methode: [`sendConfiguredEmail(emailId)`](#wsemails-sendconfiguredemail). Sie versendet die E-Mail, deren ID dem Namen der `messages`-Konfiguration entspricht. Wenn der Aufruf ungeschützt im Template steht, wird die E-Mail bei jedem Seitenaufruf versendet. Um dies zu vermeiden, sollten Sie ihn immer mit einer Bedingung umschließen, die nur im gewünschten Fall zutrifft, etwa nach dem erfolgreichen Absenden eines Formulars. So vermeiden Sie einen versehentlichen Mehrfachversand. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsEmails` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsEmails | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "sendConfiguredEmail": "ƒ()" } ``` Anmerkung: `"ƒ()"` kennzeichnet eine Funktion. **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ----------------------- | ---------------- | ----------------------------------------------------- | | `sendConfiguredEmail()` | – | Versendet eine unter `messages` konfigurierte E-Mail. | *** ## Templates Der E-Mail-Versand kann von jedem Template aus ausgelöst werden, aber nur kontrolliert (siehe [Grundkonzept](#grundkonzept)). Typische Einsatzgebiete sind Kontaktformulare, Bestätigungen oder Benachrichtigungen nach bestimmten Aktionen. *** ## Variablen Für `$wsEmails` stehen keine Variablen zur Verfügung. *** ## Methoden ### \$wsEmails.sendConfiguredEmail() Versendet eine E-Mail, die in der Shop-Konfiguration unter `messages` definiert wurde. Die E-Mail-ID entspricht dem Namen der Konfiguration. **Signatur**\ `$wsEmails.sendConfiguredEmail(emailId)` ## **Rückgabe**\\ **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | --------- | ------- | ----------- | ---------------------------------------------------------------------------------------------- | | `emailId` | string | ja | ID der E-Mail aus der `messages`-Konfiguration (z. B. `"orderConfirmation"`, `"contactForm"`). | Aufruf (immer mit einer Bedingung umschließen, siehe Beispiel): ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ $wsEmails.sendConfiguredEmail("contactForm") }} ``` *** ## Aktionen Für `$wsEmails` stehen keine Aktionen zur Verfügung. *** ## Beispiele ### E-Mail nur nach erfolgreichem Formular versenden Dieses Beispiel koppelt den Versand an den Erfolg einer Formular-Aktion: Erst wenn das Formular erfolgreich abgesendet wurde (`success`), wird die konfigurierte E-Mail ausgelöst. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $contact = $wsActions.create("ContactForm") }}
    {{ if $contact.success }} {{ $wsEmails.sendConfiguredEmail("contactForm") }} Vielen Dank, Ihre Nachricht wurde versendet. {{ /if }} ``` **Ergebnis** \ Die E-Mail geht nur dann raus, wenn das Formular erfolgreich abgesendet wurde. Ein bloßes Neuladen der Seite löst keinen Versand aus. Der Aktionsname `ContactForm` und die E-Mail-ID `contactForm` sind Platzhalter. Setzen Sie die in Ihrem Shop konfigurierten Namen ein und prüfen Sie, dass der Versand ausschließlich im `success`-Fall erfolgt. *** ## Weiterführende Links * [messages - Ereignisgesteuerte E-Mails](/konfiguration/messages-ereignisgesteuerte-e-mails) – legt die versendbaren E-Mails (Inhalt, Empfänger, ID) an, auf die `sendConfiguredEmail()` zugreift. * [\$wsActions](/frontend/referenz/module/wsactions) – liefert den `success`-Status, mit dem Sie den Versand absichern. # $wsExternalData - Externe Daten Source: https://dokumentation.websale.de/frontend/referenz/module/wsexternaldata Externe JSON-Daten aus dem shop-eigenen S3-Bucket in Templates laden, auflisten und Fehler behandeln – für CMS-Inhalte, Feeds und Drittdaten. Mit dem `$wsExternalData`-Modul laden Sie dateibasierte externe Daten (JSON) aus dem shop-eigenen S3 in Ihre Templates und verarbeiten sie dort. Typische Anwendungsfälle sind Zusatzinformationen, die nicht aus den Standard-Shopdaten stammen, beispielsweise PDF-Listen zu einem Produkt oder Inhalte aus WEBSALE-Komponenten wie einer [Strapi](/strapi-cms)-Instanz. Auf dieser Seite geht es um den lesenden Zugriff auf abgelegte Dateien. Das Befüllen der Buckets (Upload, Strapi-Export) erfolgt über die [Datenschnittstelle](/schnittstellen/externe-datenschnittstelle-datei-bucket-basiert), nicht über dieses Modul. *** ## Grundkonzept `$wsExternalData` hat keine eigenen Variablen. Stattdessen laden Sie Daten über eine Methode in eine eigene [Template-Variable](/frontend/referenz/variablen) und arbeiten dann mit dieser weiter. Der Ablauf ist immer derselbe: 1. **Laden** - `load()` liest eine Datei und gibt ihren Inhalt zurück; das Ergebnis weisen Sie einer Variable zu (z. B. `$data`). 2. **Prüfen** - Sie prüfen mit `{{ if $data }}`, ob das Laden geklappt hat. 3. **Ausgeben** - erst danach iterieren oder zeigen Sie die Inhalte. ### Immer auf Erfolg prüfen Externe Daten können fehlen oder nicht erreichbar sein (falscher Pfad, leerer Bucket, Zugriffsproblem). Umschließen Sie die Ausgabe deshalb immer mit `{{ if $data }}` – sonst entstehen leere Platzhalter oder „tote" HTML-Strukturen. Im Fehlerfall liefert [`getLastError()`](#wsexternaldata-getlasterror) eine Diagnosemeldung (nur für die Entwicklung, nicht fürs Frontend). ### Die drei Methoden im Zusammenspiel * [`load()`](#wsexternaldata-load) lädt den Inhalt einer Datei (Map oder Liste, je nach JSON). * [`read()`](#wsexternaldata-read) listet die Dateien eines Verzeichnisses auf, ohne deren Inhalt zu laden – nützlich, um dynamisch zu ermitteln, welche Dateien vorhanden sind, und diese anschließend mit `load()` zu laden. * [`getLastError()`](#wsexternaldata-getlasterror) gibt die letzte Fehlermeldung zurück. ### Datenquellen (`source`) Beide Lade-Methoden kennen zwei Quellen: `user` (Bucket `external-data`, Standard) für eigene, projektbezogene Dateien und `system` (Bucket `system`) für Dateien, die WEBSALE-Komponenten bereitstellen (z. B. Strapi-Exporte). ### Hinweis zum Zeitpunkt `load()` und `read()` greifen beim Seitenaufbau auf das S3 zu. Jeder Aufruf ist ein Netzwerkzugriff. Somit laden Sie gezielt, was die Seite braucht, statt unnötig viele Dateien pro Seitenaufruf. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsExternalData` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsExternalData | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "load": "ƒ()", "read": "ƒ()", "getLastError": "ƒ()" } ``` Anmerkung: `"ƒ()"` kennzeichnet eine Funktion. **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ---------------- | ---------------- | ---------------------------------------------------------- | | `load()` | map \| list | Lädt den Inhalt einer JSON-Datei. | | `read()` | list | Listet die Dateien eines Verzeichnisses auf (ohne Inhalt). | | `getLastError()` | string | Letzte Fehlermeldung von `load()` / `read()`. | *** ## Grundkonzept `$wsExternalData` hat keine eigenen Variablen. Stattdessen laden Sie Daten über eine Methode in eine eigene [Template-Variable](/frontend/referenz/variablen) und arbeiten dann mit dieser weiter. Der Ablauf ist immer derselbe: 1. **Laden** - `load()` liest eine Datei und gibt ihren Inhalt zurück; das Ergebnis weisen Sie einer Variable zu (z. B. `$data`). 2. **Prüfen** - Sie prüfen mit `{{ if $data }}`, ob das Laden geklappt hat. 3. **Ausgeben** - erst danach iterieren oder zeigen Sie die Inhalte. ### Immer auf Erfolg prüfen Externe Daten können fehlen oder nicht erreichbar sein (falscher Pfad, leerer Bucket, Zugriffsproblem). Umschließen Sie die Ausgabe deshalb immer mit `{{ if $data }}` – sonst entstehen leere Platzhalter oder „tote" HTML-Strukturen. Im Fehlerfall liefert [`getLastError()`](#wsexternaldata-getlasterror) eine Diagnosemeldung (nur für die Entwicklung, nicht fürs Frontend). ### Die drei Methoden im Zusammenspiel * [`load()`](#wsexternaldata-load) lädt den Inhalt einer Datei (Map oder Liste, je nach JSON). * [`read()`](#wsexternaldata-read) listet die Dateien eines Verzeichnisses auf, ohne deren Inhalt zu laden – nützlich, um dynamisch zu ermitteln, welche Dateien vorhanden sind, und diese anschließend mit `load()` zu laden. * [`getLastError()`](#wsexternaldata-getlasterror) gibt die letzte Fehlermeldung zurück. ### Datenquellen (`source`) Beide Lade-Methoden kennen zwei Quellen: `user` (Bucket `external-data`, Standard) für eigene, projektbezogene Dateien und `system` (Bucket `system`) für Dateien, die WEBSALE-Komponenten bereitstellen (z. B. Strapi-Exporte). ### Hinweis zum Zeitpunkt `load()` und `read()` greifen beim Seitenaufbau auf das S3 zu. Jeder Aufruf ist ein Netzwerkzugriff. Somit laden Sie gezielt, was die Seite braucht, statt unnötig viele Dateien pro Seitenaufruf. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsExternalData` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsExternalData | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "load": "ƒ()", "read": "ƒ()", "getLastError": "ƒ()" } ``` Anmerkung: `"ƒ()"` kennzeichnet eine Funktion. **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ---------------- | ---------------- | ---------------------------------------------------------- | | `load()` | map \| list | Lädt den Inhalt einer JSON-Datei. | | `read()` | list | Listet die Dateien eines Verzeichnisses auf (ohne Inhalt). | | `getLastError()` | string | Letzte Fehlermeldung von `load()` / `read()`. | *** ## Templates Externe Daten können in jedes Template geladen werden, je nach Anwendungsfall beispielsweise auf Produktdetailseiten (Zusatzdaten), Kategorieseiten (Zusatzlisten) oder Content-Seiten. *** ## Variablen `$wsExternalData` stellt keine eigenen Variablen bereit. Die geladenen Daten sind in der Template-Variable gespeichert, der Sie das Ergebnis von `load()` zuweisen (siehe [Grundkonzept](#grundkonzept)). *** ## Methoden ### \$wsExternalData.load() Lädt den Inhalt einer Datei aus der [externen Datenschnittstelle](/schnittstellen/externe-datenschnittstelle-datei-bucket-basiert#2-datenablage-im-s3) und gibt ihn, je nach JSON-Struktur, als Map (bei einem Objekt) oder Liste (bei einem Array) zurück, um ihn im Template auszugeben (z. B. PDFs, Zusatzattribute, CMS-Inhalte). **Signatur**\ `$wsExternalData.load(file, options)` **Rückgabe**\ `map` | `list` – abhängig von der JSON-Struktur, im Fehlerfall leer/null. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | --------- | ------- | ----------- | ------------------------------------------------------------------------ | | `file` | string | ja | Pfad zur Datei innerhalb der Quelle (z. B. `products/product_123.json`). | | `options` | map | ja | Format- und Quell-Optionen (siehe Tabelle). | **Optionen (`options`)** | **Key** | **Typ** | **Pflicht** | **Default** | **Beschreibung** | | ---------- | ------- | ----------- | ----------- | ------------------------------------------------------------------------------------------ | | `type` | string | ja | – | Dateiformat. Aktuell erlaubt: `json`. | | `source` | string | nein | `user` | Datenquelle: `user` (Bucket `external-data`) oder `system` (Bucket `system`). | | `maxDepth` | int | nein | `7` | Begrenzt die Auslese-Tiefe verschachtelter JSON-Strukturen; tiefere Ebenen werden gekürzt. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $data = $wsExternalData.load("products/product_123.json", { type: "json" }) }} {{ if $data }} {{= $data | json }} {{ /if }} ``` ### \$wsExternalData.read() Listet alle Dateien eines Verzeichnisses der externen Datenschnittstelle auf (optional inkl. Unterordnern) und gibt deren Pfade als Liste zurück. Der Dateiinhalt wird nicht geladen, nutzen Sie dafür anschließend `load()`. Hilfreich, wenn dynamisch ermittelt werden soll, welche Dateien in einem Verzeichnis vorhanden sind. **Signatur**\ `$wsExternalData.read(path, options)` **Rückgabe**\ `list` – Pfade der gefundenen Dateien. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | --------- | ------- | ----------- | -------------------------------------------------------------- | | `path` | string | ja | Verzeichnis-Pfad innerhalb der Quelle (z. B. `json/Deutsch/`). | | `options` | map | nein | Quell- und Filter-Optionen (siehe Tabelle). | **Optionen (`options`)** | **Key** | **Typ** | **Pflicht** | **Default** | **Beschreibung** | | ----------- | ------- | ----------- | ----------- | --------------------------------------------------------------------------------------------------------------- | | `source` | string | nein | `user` | Datenquelle: `user` oder `system`. | | `recursive` | bool | nein | `false` | `true`: auch Unterordner durchsuchen. | | `glob` | bool | nein | – | Schaltet die Muster-Interpretation ein/aus. Erwartet einen **Boolean**, **kein** Muster-String (siehe Hinweis). | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $files = $wsExternalData.read("json/Deutsch/", { source: "system" }) }} {{ if $files }}
      {{ foreach $file in $files }}
    • {{= $file }}
    • {{ /foreach }}
    {{ /if }} ``` ### \$wsExternalData.getLastError() Gibt die letzte Fehlermeldung als String zurück, wenn bei `load()` oder `read()` ein Fehler aufgetreten ist (z. B. Datei nicht vorhanden, Zugriff nicht möglich). Die Meldung ist für die Fehlersuche gedacht und sollte nicht im Frontend für Kunden ausgegeben werden. **Signatur**\ `$wsExternalData.getLastError()` **Rückgabe**\ `string` – Fehlerbeschreibung, oder leer/null, wenn kein Fehler vorliegt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $error = $wsExternalData.getLastError() }} {{ if $error }} {{ /if }} ``` Geben Sie die Fehlermeldung nur in der Konsole (Entwicklung) aus, nie sichtbar ins Frontend. Der `autoescape "js"`-Block stellt sicher, dass Sonderzeichen in der Meldung das umgebende Skript nicht zerstören. *** ## Aktionen Für `$wsExternalData` stehen keine Aktionen zur Verfügung. *** ## Beispiele ### Produkt-Zusatzdaten (PDF-Liste) laden und ausgeben Ein häufiger Fall: Zu einem Produkt werden über eine JSON-Datei PDF-Verlinkungen gepflegt. Für Produkt `137497` liegt unter `products/137497.json`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "pdf": [ { "link": "https://medienserver.example/faq.pdf", "name": "Häufige Fragen und Antworten" }, { "link": "https://medienserver.example/anleitung.pdf", "name": "Bedienungsanleitung" } ] } ``` Die Datei laden, auf Erfolg prüfen und die PDFs als Liste ausgeben: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $data = $wsExternalData.load("products/137497.json", { type: "json" }) }} {{ if $data and $data.pdf }} {{ /if }} ``` **Ergebnis** \ Eine Liste verlinkter PDFs. Aber nur, wenn die Datei geladen wurde und ein `pdf`-Array enthält. ### CMS-/Strapi-Inhalte aus der Quelle `system` laden Aus dem `system`-Bucket lädt man typischerweise Strapi-Exporte. In `Content` mischt Strapi verschiedene Block-Typen. Jeder Block trägt ein `__component`-Feld, über das Sie gezielt filtern. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cms = $wsExternalData.load("json/Deutsch/ws_start.json", { source: "system", type: "json", maxDepth: 20 }) }} {{ if $cms }} {{ foreach $item in $cms.attributes.Content }} {{ if $item.__component == "elemente.categories" }} {{ include "components/cms/categories.htm" with $cContentItem = $item }} {{ /if }} {{ /foreach }} {{ /if }} ``` Ein Block in der JSON-Datei sieht z. B. so aus: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": 1, "__component": "elemente.categories", "CategoryIDs": "10-04418,2-06719,3-82749", "ClassList": "row mb-3" } ``` **Ergebnis** \ Nur Blöcke vom Typ `elemente.categories` werden über die passende Komponente gerendert. Andere Block-Typen werden übersprungen. ### Dateien eines Verzeichnisses auflisten Mit `read()` ermitteln Sie, welche Dateien vorhanden sind, ohne deren Inhalt zu laden. Den Inhalt laden Sie anschließend gezielt mit `load()`. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $files = $wsExternalData.read("json/Deutsch/", { source: "system" }) }} {{ if $files }} {{ foreach $file in $files }} {{ var $data = $wsExternalData.load($file, { source: "system", type: "json" }) }} {{ if $data }} {{ /if }} {{ /foreach }} {{ /if }} ``` **Ergebnis** \ Alle passenden Dateien werden gefunden und einzeln geladen. ### Laden mit Fehlerbehandlung Nur bei Erfolg ausgeben, andernfalls die Fehlermeldung in die Konsole schreiben. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $data = $wsExternalData.load("products/product_123.json", { type: "json" }) }} {{ if $data }} {{= $data | json }} {{ else }} {{ var $error = $wsExternalData.getLastError() }} {{ if $error }} {{ /if }} {{ /if }} ``` **Ergebnis** \ Bei Erfolg erscheinen die Daten, sonst landet die Fehlerursache in der Browser-Konsole. Wenn Sie einen Pfad aus mehreren Bestandteilen zusammensetzen, können Sie ein Array mit `| join` zu einem String verbinden, bevor Sie es an `load()` / `read()` übergeben. Für einen festen Pfad genügt der String direkt (wie in den Beispielen oben). *** ## Weiterführende Links * [Externe Datenschnittstelle (Datei-/Bucket-basiert)](/schnittstellen/externe-datenschnittstelle-datei-bucket-basiert) – legt fest, welche Buckets/Quellen es gibt und wie Dateien abgelegt werden. * [join-Funktion](/frontend/referenz/funktionen#join) – verbindet ein Array zu einem String (für zusammengesetzte Pfade). # $wsForm - Formulare Source: https://dokumentation.websale.de/frontend/referenz/module/wsform Formularstrukturen laden, Formulare rendern und die übermittelten Daten eines abgeschickten Formulars im Frontend lesen – Kontakt, Frage, Inquiry. Mit dem `$wsForm`-Modul arbeiten Sie im Frontend mit Formularen. Sie laden die Struktur eines Formulars (Felder, Labels, Validierungen), um es auszugeben, und lesen nach dem Absenden die übermittelten Daten. Auf dieser Seite geht es um das Laden und Lesen von Formulardaten. Das Absenden selbst (und weitere Formular-Aktionen) ist unter [Aktionen → Inquiry](/frontend/referenz/aktionen/inquiry) dokumentiert; die Formulare werden in der [inquiry-Konfiguration](/konfiguration/inquiry-formulare) angelegt. *** ## Grundkonzept Ein Formular durchläuft vier Schritte, die `$wsForm` zusammen mit der `InquirySend`-Aktion abbildet: 1. **Struktur laden** – [`loadType(formId)`](#wsform-loadtype) liefert die Felder eines Formulars (z. B. `"contact"`), damit Sie es im Frontend ausgeben können. 2. **Absenden** – der Kunde sendet das Formular über die Aktion `InquirySend` ([\$wsActions](/frontend/referenz/module/wsactions)). Das Formular schickt das versteckte Feld `formId` mit dem Formularnamen mit. Die Formularfelder werden mit dem Präfix `form.` benannt (z. B. `form.subject`). 3. **Anfrage-ID erhalten** – nach erfolgreichem Absenden liegt die Anfrage-ID vor (in `InquirySend.successInfo.inquiryId`, ebenso in [`$wsForm.inquiryId`](#wsform-inquiryid)). 4. **Daten lesen** – [`load(inquiryId)`](#wsform-load) liefert die übermittelten Daten zur Anfrage-ID, z. B. für eine Bestätigungsanzeige. Zusätzlich listet [`loadAllTypes()`](#wsform-loadalltypes) alle Formulartypen des Shops auf. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsForm` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsForm | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "inquiryId": "...", "load": "ƒ()", "loadAllTypes": "ƒ()", "loadType": "ƒ()" } ``` Anmerkung: `"ƒ()"` kennzeichnet eine Funktion. **Variablen in der Übersicht** | **Variable** | **Typ** | **Beschreibung** | | ------------ | ------- | ------------------------------------------------------- | | `inquiryId` | string | Anfrage-ID nach erfolgreichem Absenden eines Formulars. | **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ---------------- | ---------------- | ------------------------------------------------------------ | | `loadType()` | map | Lädt die Struktur eines Formulars anhand des Formularnamens. | | `loadAllTypes()` | array | Lädt alle verfügbaren Formulartypen des Shops. | | `load()` | map | Lädt die übermittelten Daten einer abgeschickten Anfrage. | *** ## Templates Formulare werden überall im Shop verwendet, beispielsweise im Kontaktformular, beim Widerrufsformular oder bei der Passwort-Wiederherstellung. *** ## Variablen ### \$wsForm.inquiryId Enthält die eindeutige Anfrage-ID nach dem erfolgreichen Absenden eines Formulars. Mit dieser ID rufen Sie die übermittelten Daten über [`load()`](#wsform-load) ab. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Anfrage-ID: {{= $wsForm.inquiryId }} ``` *** ## Methoden ### \$wsForm.loadType() Lädt die Struktur eines Formulars (Felder, Labels, Validierungen) anhand des Formularnamens. Nutzen Sie die zurückgegebenen Felder, um das Formular zu rendern. **Signatur**\ `$wsForm.loadType(formId)` **Rückgabe**\ **Rückgabe**\ `map` mit den Formular-Eigenschaften: `name` (Formularname), `fields` (Feldliste), `email` (E-Mail-Konfiguration des Formulars), `loadField` (Methode zum Laden eines einzelnen Feldes) und `nodeId` (ID des Konfigurationsknotens, als zweiter Parameter für [`$wsOptions.get(name, nodeId)`](/frontend/referenz/module/ws-options-template-optionen)). **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | -------- | ------- | ----------- | --------------------------------------- | | `formId` | string | ja | Name des Formulars (z. B. `"contact"`). | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $field in $wsForm.loadType("contact").fields }} {{= $field.label }} ({{= $field.name }}){{ if $field.required }} *{{ /if }} {{ /foreach }} ``` #### Eigenschaften eines Feld-Objekts Ist dem Formular ein [RuleSet](https://dokumentation.websale.de/konfiguration/inquiry-formulare#inquiry-ruleset-regelbasierte-feldsteuerung) zugewiesen, werden `label`, `required`, `visible` und `defaultValue` automatisch durch dessen Regeln angepasst. | **Eigenschaft** | **Rückgabe-Typ** | **Beschreibung** | | --------------- | ---------------- | ------------------------------------------------------------ | | `name` | string | Technischer Feldname. | | `label` | string | Anzeigename des Feldes. | | `required` | bool | Pflichtfeldkennzeichen. | | `validations` | array | Validierungsregeln des Feldes (je `type` und `name`). | | `defaultValue` | string | Standardwert; zum Vorbelegen, wenn der Wert leer ist. | | `value` | string | Aktueller Wert (wird bei der Aktion `inquiryCheck` befüllt). | | `visible` | bool | Ob das Feld angezeigt werden soll. | ### \$wsForm.loadAllTypes() Lädt alle verfügbaren Formulartypen des Shops. **Signatur**\ `$wsForm.loadAllTypes()` **Rückgabe**\ `array` – Liste aller Formulartypen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $formType in $wsForm.loadAllTypes() }} Formular: {{= $formType.name }} {{ /foreach }} ``` ### \$wsForm.load() Lädt die übermittelten Daten einer abgeschickten Formularanfrage. Übergeben Sie die Anfrage-ID, die Sie nach dem Absenden erhalten haben. **Signatur**\ `$wsForm.load(inquiryId)` **Rückgabe**\ `map` – die Anfragedaten (Struktur siehe unten). **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | ----------------------------- | | `inquiryId` | string | ja | ID der abgeschickten Anfrage. | #### Struktur der Anfragedaten | **Eigenschaft** | **Rückgabe-Typ** | **Beschreibung** | | --------------- | ---------------- | -------------------------------------------------------- | | `id` | string | Eindeutige ID der Anfrage. | | `formId` | string | Name des verwendeten Formulars. | | `createdAt` | string | Zeitpunkt des Absendens (ISO 8601, UTC). | | `submitter` | map | Daten des Absenders (`email`, `sessionId`, `ipAddress`). | | `form` | map | Eingegebene Felddaten, je Feld `{ label, value }`. | Auf ein einzelnes Feld greifen Sie über seinen technischen Namen zu, z. B. `form.firstName.value` und `form.firstName.label`. *** ## Aktionen Aktionen zu diesem Modul (Absenden, Prüfen) sind separat dokumentiert: [Aktionen → Inquiry](/frontend/referenz/aktionen/inquiry). *** ## Beispiele ### Formularfelder rendern `loadType()` liefert die Felder eines Formulars, aus denen Sie die Eingabefelder erstellen. Die Feldnamen erhalten das Präfix `form.`. Ausgeblendete Felder (`visible = false`) überspringen Sie und Pflichtfelder kennzeichnen Sie mit required. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $field in $wsForm.loadType("contact").fields }} {{ if $field.visible }} {{ /if }} {{ /foreach }} ``` **Ergebnis** \ Für jedes sichtbare Feld des Kontaktformulars gibt es ein beschriftetes Eingabefeld mit dem Präfix `form-`. Pflichtfelder sind mit einem Sternchen (\*) markiert. Das Absenderfeld `email` ist kein `loadType`-Feld und wird separat als `input name="email"` ergänzt. ### Vollständiges Kontaktformular mit Absenden und Bestätigung Dieses Beispiel zeigt den kompletten Loop: Formular mit den nötigen versteckten Feldern und `form.`-Präfix rendern, bei Fehler die Eingaben erhalten und Feldfehler anzeigen, bei Erfolg die Daten über `load()` lesen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $action = $wsActions.create("InquirySend") }}
    {{ if $action.success }} {{ var $inquiry = $wsForm.load($action.successInfo.inquiryId) }}

    Danke für Ihre Anfrage (ID {{= $inquiry.id }}).

    Bestätigung an: {{= $inquiry.submitter.email }}

    {{ else }} {{ if $action.errorsByField.subject }} {{= $action.errorsByField.subject[0].text }} {{ /if }} {{ if $action.errorsByField.comment }} {{= $action.errorsByField.comment[0].text }} {{ /if }} {{ /if }}
    ``` **Ergebnis** \ Das Formular erscheint vor dem Absenden. Bei fehlerhafter Eingabe bleiben die Werte erhalten und die Feldfehler werden angezeigt. Nach erfolgreichem Absenden erscheint die Bestätigung mit der Anfrage-ID. Nutzt das Formular ein Captcha (z. B. reCAPTCHA v3), gehört es hinter `{{ if $wsConsent.checkAllowed("recaptchav3") }}` und braucht ein Feld `` sowie die Captcha-Komponente. Siehe [\$wsConsent](/frontend/referenz/module/wsconsent). Beispiel einer von `load()` zurückgegebenen Struktur (Felder gemäß dem echten Kontaktformular; die `load()`-Struktur selbst ist noch zu bestätigen): ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "52ad06427c68738c", "formId": "contact", "createdAt": "2025-04-14T06:43:57Z", "submitter": { "email": "kundin@beispiel.de", "ipAddress": "95.90.217.XXX", "sessionId": "c5a37018627bf18e…" }, "form": { "subject": { "label": "Betreff", "value": "Test-Anfrage" }, "comment": { "label": "Ihre Nachricht", "value": "Bitte um weitere Infos" } } } ``` *** ## Weiterführende Links * [Aktionen → Inquiry](/frontend/referenz/aktionen/inquiry) – das Absenden und Prüfen von Formularen (`InquirySend`, `inquiryCheck`). * [inquiry - Formulare](/konfiguration/inquiry-formulare) – legt die Formulare und Felder an, inkl. RuleSet. * [actions - Formulare](/konfiguration/actions-fehlertexte-e-mails/actions-formulare) – Konfiguration der Formular-Aktionen. # $wsInventory - Lagerbestand Source: https://dokumentation.websale.de/frontend/referenz/module/wsinventory Lagerbestand, Verfügbarkeit und Reservierungszeiten von Produkten und Varianten im Warenkorb im Frontend lesen und Statusanzeigen im Shop ausgeben. Mit dem `$wsInventory`-Modul lesen Sie Lagerbestände und Verfügbarkeiten von Produkten sowie die Reservierungszeit eines Warenkorb-Eintrags. Typische Anwendungsfälle sind Ampel-Anzeigen (grün/gelb/rot), Verfügbarkeitshinweise auf Produktseiten und der ablaufende Reservierungs-Timer im Warenkorb. Auf dieser Seite geht es um das Lesen und Anzeigen von Bestandsdaten. Eine Reservierung kann über die Aktion `InventoryReserve` ([\$wsActions](/frontend/referenz/module/wsactions)) verlängert werden. Die [Storefront-API Lagerbestand](/schnittstellen/storefront-api/storefront-api-lagerbestand) behandelt serverseitige Bestandsdaten. *** ## Grundkonzept `$wsInventory` liefert zwei verschiedene Datenpunkte: * [`load(productId)`](#wsinventory-load) – die Bestandsdaten eines Produkts (Verfügbarkeit, Stückzahl, Ampelstatus). * [`loadReservation(basketItemId)`](#wsinventory-loadreservation) – die verbleibende Reservierungszeit eines Warenkorb-Eintrags. ### Zuerst auf aktive Lagerverwaltung prüfen Die Bestandsdaten sind nur aussagekräftig, wenn für das Produkt die Lagerverwaltung aktiv ist. Prüfen Sie deshalb immer zuerst `active`, bevor Sie Stückzahl, Ampel oder Lieferstatus anzeigen, ansonsten zeigen Sie Werte an, die für dieses Produkt gar nicht gepflegt werden. ### Ampel-Logik `state` fasst die Verfügbarkeit als Ampel zusammen: `green` (ausreichend vorrätig), `yellow` (wenige Stück) und `red` (ausverkauft oder sehr knapp). Damit zeigen Sie dem Kunden auf einen Blick, wie es um die Lieferbarkeit steht, ohne selbst Schwellen zu berechnen. ### Reservierungs-Lebenszyklus Wird ein Produkt in den Warenkorb gelegt, ist es für eine bestimmte Zeit reserviert. `loadReservation()` liefert die verbleibende Zeit in Sekunden (`duration`). Läuft sie ab (`duration <= 0`), kann der Kunde über die Aktion `InventoryReserve` erneut reservieren. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsInventory` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsInventory | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "load": "ƒ()", "loadReservation": "ƒ()" } ``` Anmerkung: `"ƒ()"` kennzeichnet eine Funktion. **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ------------------- | ---------------- | ----------------------------------------------------- | | `load()` | map | Lädt die Lagerbestandsdaten eines Produkts. | | `loadReservation()` | map | Lädt die Reservierungsdaten eines Warenkorb-Eintrags. | *** ## Templates Bestands- und Verfügbarkeitsinformationen werden typischerweise dort geladen, wo Produkte erscheinen: Startseite, Kategorieliste, Suchergebnisse, Produktdetailseite und Warenkorb. *** ## Variablen Für `$wsInventory` stehen keine eigenen Variablen zur Verfügung. Die Daten werden über die Methoden geladen. *** ## Methoden ### \$wsInventory.load() Lädt die Lagerbestandsdaten eines Produkts. **Signatur**\ `$wsInventory.load(productId)` **Rückgabe**\ `map` – Lagerbestandsdaten (siehe Tabelle). **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | ---------------- | | `productId` | string | ja | ID des Produkts. | **Rückgabewerte** | **Eigenschaft** | **Typ** | **Beschreibung** | | ------------------ | ------- | ------------------------------------------------------------------------------------------------------- | | `active` | bool | `true`, wenn die Lagerverwaltung für dieses Produkt aktiv ist. | | `amount` | int | Verfügbare Stückzahl (kann `null` sein, wenn der Bestand nicht gezählt wird). | | `amountInStock` | int | Am Lager befindliche Menge (häufig `null`; im Test nur bei ausverkauften Produkten als `0` beobachtet). | | `amountNotInStock` | int | Nicht am Lager befindliche Menge (häufig `null`). | | `state` | string | Ampelstatus: `green`, `yellow` oder `red`. | | `soldOut` | bool | `true`, wenn das Produkt ausverkauft ist. | | `deliveryText` | string | Lieferstatus-Text (z. B. „Nur noch wenige Stück auf Lager"). | | `messageLimit` | int | Stückzahl, ab der `deliveryText` angezeigt wird. | | `splitDelivery` | bool | `true`, wenn auch bei Teillieferung bestellt werden kann. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $inventory = $wsInventory.load($product.id) }} {{ if $inventory.active }} {{= $inventory.deliveryText }} – verfügbar: {{= $inventory.amount }} Stück {{ /if }} ``` ### \$wsInventory.loadReservation() Lädt die Reservierungsdaten eines Warenkorb-Eintrags. **Signatur**\ `$wsInventory.loadReservation(basketItemId)` **Rückgabe**\ `map` – Reservierungsdaten. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | -------------- | ------- | ----------- | ----------------------------------------------------------------------------------------------------------------- | | `basketItemId` | string | ja | ID des Warenkorb-Eintrags (Eintrags-Hash, siehe [\$wsBasket](/frontend/referenz/module/wsbasket#wsbasket-items)). | **Rückgabewerte** | **Eigenschaft** | **Typ** | **Beschreibung** | | --------------- | ------- | ------------------------------------------------------------------------- | | `duration` | int | Verbleibende Reservierungszeit in Sekunden (`<= 0` bedeutet abgelaufen). | | `reservedUntil` | string | Zeitpunkt des Ablaufs (ISO 8601, UTC; einen `date`-Filter gibt es nicht). | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $reservation = $wsInventory.loadReservation($basketItem.id) }} {{ if $reservation }} {{ if $reservation.duration > 0 }} Reserviert für {{= $reservation.duration }} Sekunden. {{ else }} Reservierung abgelaufen. {{ /if }} {{ /if }} ``` *** ## Aktionen `$wsInventory` selbst stellt keine Aktionen bereit. Eine abgelaufene Reservierung wird über die [\$wsActions](/frontend/referenz/module/wsactions)-Aktion `InventoryReserve` erneuert (siehe [Beispiel](#reservierung-verlängern)). *** ## Beispiele ### Verfügbarkeit als Ampel anzeigen Prüft zuerst `active` und zeigt dann den Ampelstatus farbig an. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $inventory = $wsInventory.load($product.id) }} {{ if $inventory.active }} {{ switch $inventory.state }} {{ case "green" }} Verfügbar {{ case "yellow" }} Nur noch wenige Stück {{ case "red" }} Nicht lieferbar {{ /switch }} {{ /if }} ``` **Ergebnis** \ Bei aktiver Lagerverwaltung erscheint je nach `state` ein grüner, gelber oder roter Hinweis. ### Reservierungszeit als Countdown anzeigen Rechnet die Sekunden aus `duration` in Minuten und Sekunden um. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $reservation and $reservation.duration > 0 }} {{ var $sec = $reservation.duration % 60 }} {{ var $min = ($reservation.duration - $sec) / 60 }} Das Produkt ist noch {{ if $min > 0 }}{{= $min }} Minuten und {{ /if }} {{= $sec }} Sekunden für Sie reserviert. {{ else }} Ihre Reservierung ist abgelaufen. {{ /if }} ``` **Ergebnis** \ Solange die Reservierung läuft, sieht der Kunde die verbleibende Zeit. Danach den Ablauf-Hinweis. ### Reservierung verlängern Ist die Reservierung abgelaufen, bietet dieses Beispiel über die Aktion `InventoryReserve` eine Neureservierung an. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $reservation = $wsInventory.loadReservation($basketItem.id) }} {{ if $reservation }} {{ var $reserve = $wsActions.create("InventoryReserve", tag=$basketItem.id) }} {{ if $reservation.duration > 0 }} Das Produkt ist für Sie reserviert. {{ else }} Ihre Reservierung ist abgelaufen.
    {{ /if }} {{ if $reserve.success }}

    Die Menge wurde erfolgreich neu reserviert.

    {{ /if }} {{ if $reserve.error }}

    Die Reservierung konnte nicht verlängert werden.

    {{ /if }} {{ /if }} ``` **Ergebnis** \ Bei abgelaufener Reservierung erscheint ein „Neu reservieren"-Button. Nach erfolgreicher Aktion die Bestätigung. *** ## Weiterführende Links * [\$wsActions](/frontend/referenz/module/wsactions) – stellt die Aktion `InventoryReserve` zum Verlängern einer Reservierung bereit. * [\$wsBasket](/frontend/referenz/module/wsbasket) – liefert die Warenkorb-Einträge, deren ID `loadReservation()` erwartet. * [\$wsStores](/frontend/referenz/module/wsstores) – Filialfinder, relevant für die StorageID bei Click & Collect. * [Storefront-API Lagerbestand](/schnittstellen/storefront-api/storefront-api-lagerbestand) – serverseitiger Zugriff auf Bestandsdaten. # $wsLastSeenProducts - Zuletzt angesehene Produkte Source: https://dokumentation.websale.de/frontend/referenz/module/wslastseenproducts Modul $wsLastSeenProducts: zuletzt angesehene Produkte eines Kunden laden und dynamisch im Frontend als personalisierte Empfehlung anzeigen. Mit dem `$wsLastSeenProducts` Modul können Sie die zuletzt angesehenen Produkte eines Kunden dynamisch im Frontend anzeigen. Dies ermöglicht eine personalisierte Einkaufserfahrung und erleichtert dem Kunden die Navigation zu bereits betrachteten Artikeln. In diesem Abschnitt erfahren Sie, wie Sie die zuletzt angesehenen Produkte laden und darstellen können. *** ## Modulübersicht Beispiel / Ausschnitt über `$wsLastSeenProducts` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsLastSeenProducts | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "load": "ƒ()" } ``` **Anmerkung:** `ƒ()` kennzeichnet eine Funktion. **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ----------- | ---------------- | ------------------------------------------------ | | `load()` | array | Lädt die Liste der zuletzt angesehenen Produkte. | *** ## Templates Die Anzeige der zuletzt angesehenen Produkte ist in allen Templates möglich, wird jedoch üblicherweise auf der Produktdetailseite eingesetzt. Die Darstellung kann individuell angepasst werden, beispielsweise als Liste, Galerie, aufklappbares Element am unteren Browserfenster oder als Sidebar-Element. *** ## Variablen Für `$wsLastSeenProducts` stehen keine Variablen zur Verfügung. *** ## Methoden ### \$wsLastSeenProducts.load() Lädt die Liste der zuletzt angesehenen Produkte. Standardmäßig werden die letzten 10 Produkte geladen. **Signatur**\ `$wsLastSeenProducts.load()` **Rückgabe**\ `array` - Liste mit Product-Maps. **Beispiel**\ Beispiel, das die zuletzt angesehenen Produkte lädt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $lastSeen = $wsLastSeenProducts.load() }} ``` *** ## Aktionen Für `$wsLastSeenProducts` stehen keine Aktionen zur Verfügung. *** ## Beispiele für den Datenzugriff ### Prüfen, ob Produkte sich auf der Liste finden In diesem Beispiel werden die Produkte mit `$wsLastSeenProducts.load()` einer Variable zugewiesen. Enthält die Variable Daten, bedeutet dies, dass sich Produkte in der Liste befinden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cLastSeenProducts = $wsLastSeenProducts.load() }}   {{ if $cLastSeenProducts > 0 }}

    Zuletzt gesehene Produkte

    .. {{ /if }} ``` ### Produkte anzeigen Im folgenden Beispiel werden die zuletzt angesehenen Produkte aus der Variable in einer `foreach` Schleife geladen und ihre Produktdaten angezeigt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cLastSeenProducts = $wsLastSeenProducts.load() }} {{ if $cLastSeenProducts > 0 }} {{ foreach $cProduct in $cLastSeenProducts }}

    Produktname: {{= $cProduct.name }}

    {{= $cProduct.name }} ... {{ /foreach }} {{ /if }} ``` *** ## Weiterführende Links * [\$wsProducts](/frontend/referenz/module/wsproducts) # $wsMaintenance - Wartungsmodus Source: https://dokumentation.websale.de/frontend/referenz/module/wsmaintenance Modul $wsMaintenance: prüfen, ob der Shop sich im Wartungsmodus befindet, Wartungsseite anzeigen oder bestimmte Funktionen temporär deaktivieren. Mit dem `$wsMaintenance` Modul können Sie prüfen, ob der Shop sich im Wartungsmodus befindet. So können Sie Besuchern eine Wartungsseite anzeigen oder bestimmte Funktionen temporär deaktivieren. In diesem Abschnitt erfahren Sie, wie Sie den Wartungsmodus im Frontend abfragen können. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsMaintenance` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsMaintenance | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "isMaintenanceMode": "ƒ()" } ``` Anmerkung: `ƒ()` kennzeichnet eine Funktion. **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | --------------------- | ---------------- | ---------------------------------------------------------- | | `isMaintenanceMode()` | bool | Prüft, ob der Shop sich aktuell im Wartungsmodus befindet. | *** ## Templates Die Wartungsmodus-Prüfung kann auf jedem Template verwendet werden. Typischerweise wird sie eingesetzt, um eine Wartungsseite anzuzeigen oder bestimmte Funktionen zu deaktivieren. *** ## Variablen Für `$wsMaintenance` stehen keine Variablen zur Verfügung. *** ## Methoden ### \$wsMaintenance.isMaintenanceMode() Prüft, ob der Shop sich aktuell im Wartungsmodus befindet. **Signatur**\ `$wsMaintenance.isMaintenanceMode()` **Rückgabe**\ `bool` - `true` wenn Wartungsmodus aktiv, sonst `false`. **Beispiel,** das prüft, ob der Wartungsmodus aktiv ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsMaintenance.isMaintenanceMode() }} // Wartungsmodus ist aktiv {{ /if }} ``` *** ## Aktionen Für `$wsMaintenance` stehen keine Aktionen zur Verfügung. *** ## Beispiele ### Prüfen, ob der Wartungsmodus aktiv ist In diesem Beispiel wird geprüft, ob der Wartungsmodus aktiv ist und eine entsprechende Meldung ausgegeben. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsMaintenance.isMaintenanceMode() }}

    Shop ist im Wartungsmodus.

    {{ /if }} ``` *** ## Weiterführende Links * [maintenance - Wartungsmodus](/konfiguration/maintenance-wartungsmodus) # $wsNavigation - Breadcrumb Source: https://dokumentation.websale.de/frontend/referenz/module/wsnavigation Modul $wsNavigation für die Breadcrumb-Navigation: aktuellen Pfad in der Kategoriestruktur auslesen und im Frontend als Navigation darstellen. Mit dem `$wsNavigation` Modul können Sie den aktuellen Navigationspfad (Breadcrumb) des Kunden im Shop auslesen und anzeigen. Der Breadcrumb zeigt dem Kunden, wo er sich in der Kategoriestruktur befindet, und ermöglicht eine einfache Navigation zu übergeordneten Kategorien. *** ## Modulübersicht Beispiel / Ausschnitt über `$wsNavigation` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsNavigation | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "path": [ { "type": "category", "object": { "id": "...", "name": "...", "descr": "...", "active": "...", "hidden": false, "productsCount": 0, "custom": { }, "timestampCreatedAt": "...", "timestampUpdatedAt": "...", "productAssignmentType": "...", "productRules": "..." } } ] } ``` **Variablen in der Übersicht** | **Variable** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------- | | `path` | array | Pfad im Kategoriebaum, der angibt, wohin man im Shop navigiert hat. | | `[$i].type` | string | Typ der entsprechenden Position im Pfad. | | `[$i].object` | map | Kategorie-bzw. Produkt-Map. | Hinweis: Die Eigenschaften von `object` hängen vom `type` ab: * Bei type `category` stehen alle Eigenschaften aus `$wsCategories` zur Verfügung. * Bei type `product` stehen alle Eigenschaften aus `$wsProducts` zur Verfügung. * Nur das letzte Element im Pfad kann vom Typ `product` sein. *** ## Templates Standardmäßig wird der Breadcrumb in einer eigenen Datei breadcrumb.htm geladen, damit derselbe Breadcrumb überall im Shop angezeigt werden kann. Diese Datei wird typischerweise im Layout-Template eingebunden. *** ## Variablen ### \$wsNavigation.path Liste der Navigationselemente (Breadcrumb) von der Startseite bis zur aktuellen Position. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Pfad: {{= $wsNavigation.path | json }} ``` #### $wsNavigation.path\[$i].type Gibt den Typ der Position im Pfad aus: `"category"` oder `"product"`. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Typ: {{= $wsNavigation.path[0].type }} ``` #### $wsNavigation.path\[$i].object Gibt die Kategorie- bzw. Produkt-Map aus. Bei Kategorien entspricht dieser der Category-Map, bei Produkten der Product-Map. So kann auf Eigenschaften wie `name`, `id` oder `custom` zugegriffen werden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Name: {{= $wsNavigation.path[0].object.name }} ``` *** ## Methoden Für `$wsNavigation` stehen keine Methoden zur Verfügung. *** ## Aktionen Für `$wsNavigation` stehen keine Aktionen zur Verfügung. *** ## Beispiele für die Verwendung der Navigationsdaten ### Breadcrumb-Navigation Um die verfügbaren Daten der Breadcrumb-Navigation einzusehen, können Sie sich diese in einem JSON-ähnlichen Format ausgeben lassen. Dies ist hilfreich, um die Struktur und Inhalte der Breadcrumb-Navigation zu verstehen oder auch Fehler zu debuggen. ### Beispiel für die Anzeige des Breadcrumbs In diesem Beispiel wird mittels des `$wsNavigation` Moduls die aktuelle Position des Shop-Kunden in der Menüstruktur der gerade besuchten Seite angezeigt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $part in $wsNavigation.path }} {{ var $url = "" }} {{ if $part.type == "product" }} {{ $url = $wsViews.url("Product", {productId: $part.object.id}) }} {{ else }} {{ $url = $wsViews.url("Category", {id: $part.object.id}) }} {{ /if }} {{= $part.object.name }} {{ /foreach } ``` ### Beispiel für Verlinkungen erzeugen In diesem Beispiel wird gezeigt wie das letzte Element eines Breadcrumbs mit oder ohne Verlinkung erzeugt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $part in $wsNavigation.path }} {{ var $url = "" }} ... {{ var $last = $part is $wsNavigation.path|last }} {{ if not $last }}{{/if}} {{ /foreach }} ``` *** ## Weiterführende Links * [Breadcrumb Navigation](/frontend/praxisbeispiele/navigation-und-menustrukturen/breadcrumb-navigation) * [Hauptmenü Navigation](/frontend/praxisbeispiele/navigation-und-menustrukturen/hauptmenu-navigation) * [MultiPage Checkout](/frontend/praxisbeispiele/bestellablauf-bestellfunktionen/multipage-checkout) * [Blätterfunktion](/frontend/praxisbeispiele/kategorien-suche/blatterfunktion) # $wsNewsletter - Newsletter Source: https://dokumentation.websale.de/frontend/referenz/module/wsnewsletter Modul $wsNewsletter: Zielgruppen laden, Anmeldeformulare aufbauen, Newsletter im Kundenkonto verwalten und Abmelde-Links in E-Mails bereitstellen. Mit dem `$wsNewsletter` Modul können Sie auf Newsletter-Funktionen zugreifen. Typische Anwendungsfälle sind Anmeldeformulare mit Zielgruppen-Auswahl, Newsletter-Verwaltung im Kundenkonto oder Abmelde-Links in E-Mails. In diesem Abschnitt erfahren Sie, wie Sie Zielgruppen laden und Newsletter-Formulare erstellen können. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsNewsletter` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsNewsletter | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "getTargetGroups": "ƒ()" } ``` Anmerkung: `ƒ()` kennzeichnet eine Funktion. **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ------------------- | ---------------- | -------------------------------------------- | | `getTargetGroups()` | array | Lädt die verfügbaren Newsletter-Zielgruppen. | *** ## Templates Newsletter-Formulare werden typischerweise an folgenden Stellen eingesetzt: * Footer: Kompaktes Anmeldeformular mit E-Mail-Feld. * Eigene Seite: Ausführliches Formular mit Zielgruppen-Auswahl und zusätzlichen Feldern. * Kundenkonto: Verwaltung der Newsletter-Abonnements. *** ## Variablen Für `$wsNewsletter` stehen keine Variablen zur Verfügung. *** ## Methoden ### \$wsNewsletter.getTargetGroups() Lädt die verfügbaren Newsletter-Zielgruppen. **Signatur**\ `$wsNewsletter.getTargetGroups()` **Rückgabe**\ `array` - Liste der verfügbaren Zielgruppen. **Beispiel,** das alle Zielgruppen lädt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myTargetGroups = $wsNewsletter.getTargetGroups() }} {{ foreach $targetGroup in $myTargetGroups }} {{= $targetGroup.name }} - {{= $targetGroup.id }} {{ /foreach }} ``` *** ## Aktionen Für `$wsNewsletter` stehen keine Aktionen zur Verfügung. *** ## Beispiele ### Anmeldeformular mit Zielgruppen-Auswahl ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $targetGroups = $wsNewsletter.getTargetGroups() }} {{ if $targetGroups }}

    Newsletter auswählen:

    {{ foreach $group in $targetGroups }} {{ /foreach }} {{ /if }} ``` *** ## Weiterführende Links * [newsletter - Newsletter](/konfiguration/newsletter-newsletter) * [actions - Newsletter](/konfiguration/actions-fehlertexte-e-mails/actions-newsletter) # $wsOptIn - Opt-In-Prozesse Source: https://dokumentation.websale.de/frontend/referenz/module/wsoptin Modul $wsOptIn für Token-Prozesse: E-Mail-Verifizierung, Newsletter-Bestätigung und Passwort-Zurücksetzen über Opt-In-Links umsetzen. Mit dem `$wsOptIn` Modul können Sie Token-basierte Opt-In-Prozesse im Frontend umsetzen. Typische Anwendungsfälle sind E-Mail-Verifizierung, Newsletter-Bestätigung oder Passwort-Zurücksetzen. In diesem Abschnitt erfahren Sie, wie Sie Opt-In-Links erstellen und die Token-Gültigkeit prüfen können. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsOptIn` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsOptIn | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "current": { "valid": true, "token": "..." }, "createTokenUrl": "ƒ()" } ``` Anmerkung: `ƒ()` kennzeichnet eine Funktion. **Variablen und Methoden in der Übersicht:** | **Variable** | **Typ** | **Beschreibung** | | ------------------ | ------- | --------------------------------------------------------------------------------------- | | `current` | map | Gibt eine Map mit Infos zum aktiven Token aus, falls dieser im Request übergeben wurde. | | `valid` | bool | Gibt `true` aus, wenn der übergebene Token gültig ist. | | `token` | string | Gibt den übergebenen Token als Text aus. | | `createTokenUrl()` | string | Erstellt eine Opt-In-URL mit einem sicheren Token. | *** ## Templates Typischerweise wird das `$wsOptIn` Modul bei Kontofunktionen wie zum Beispiel beim Passwort-Zurücksetzen, oder beim Konto erstellen verwendet. *** ## Variablen ### \$wsOptIn.current Enthält Informationen zum Token, der in der aktuellen URL übergeben wurde. Ist `null`, wenn kein Token in der URL vorhanden ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsOptIn.current }} // Token wurde übergeben {{ /if }} ``` #### \$wsOptIn.current.valid Gibt `true / false`aus, wenn der übergebene Token gültig / ungültig ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsOptIn.current.valid }} // Token ist gültig {{ else }} // Token ist ungültig oder abgelaufen {{ /if }} ``` #### \$wsOptIn.current.token Gibt den übergebenen Token aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Token: {{= $wsOptIn.current.token }} ``` *** ## Methoden ### \$wsOptIn.createTokenUrl() Erstellt eine Opt-In-URL mit einem sicheren Token. Der Token wird automatisch generiert und an die angegebene URL angehängt. Diese URL kann dann per E-Mail an den Kunden gesendet werden. **Signatur**\ `$wsOptIn.createTokenUrl(url, tokenName)` **Rückgabe**\ `string` - URL mit angehängtem Token-Parameter. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | ------------------------------------------- | | `url` | string | ja | Basis-URL, an die der Token angehängt wird. | | `tokenName` | string | ja | Name des Tokens. (z.B. `“verifyEmail”`) | **Beispiel,** das eine URL mit Token für die E-Mail-Verifizierung erstellt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsOptIn.createTokenUrl($wsViews.viewUrl('account/verify.htm'), 'verifyEmail') }} ``` *** ## Aktionen Für `$wsOptIn` stehen keine Aktionen zur Verfügung. *** ## Beispiele für den Datenzugriff ### Bestätigung der E-Mail-Adresse per Opt-In-Link Nach der Erstellung eines Nutzerkontos im Shop erhält der Nutzer eine E-Mail zur Bestätigung seiner E-Mail-Adresse, z.B. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} E-Mail-Adresse bestätigen ``` Der Bestätigungslink enthält einen Token, der sicherstellt, dass nur der Empfänger die Bestätigung durchführen kann. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www.beispielshop.de/account/emailVerify.htm?token=abc123xyz ``` Wenn der Nutzer den Link klickt und die Bestätigungsseite (`emailVerify.htm`) geöffnet wird, wird geprüft, ob der Token gültig ist. Falls ja, kann er die Verifizierung durch einen Button-Click abschließen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsOptIn.current }} {{ if $wsOptIn.current.valid }} Button zum Bestätigen {{ else }} Dieser Link ist nicht länger gültig. {{ /if }} {{ else }} Ungültiger Zugriff auf die Bestätigungsseite. {{ /if }} ``` *** ## Weiterführende Links * [Aktionen](/frontend/referenz/aktionen) # $wsOrderHistory - Bestellhistorie Source: https://dokumentation.websale.de/frontend/referenz/module/wsorderhistory Vergangene Bestellungen eines eingeloggten Kunden im Frontend laden, auflisten und einzelne Bestelldetails anzeigen. Mit dem `$wsOrderHistory`-Modul lesen Sie die Bestellhistorie des aktuell eingeloggten Kunden und zeigen sie in Ihren Templates an. Damit bauen Sie typische Konto-Funktionen: eine Übersicht aller bisherigen Bestellungen und eine Detailansicht zu einer einzelnen Bestellung (z. B. als Grundlage für eine Nachbestellung). Da das Modul nur Daten des angemeldeten Kunden liefert, ist außerdem das Zusammenspiel mit dem [Account-Modul](/frontend/referenz/module/wsAccount) relevant. Auf dieser Seite geht es ausschließlich um den lesenden Zugriff auf bereits abgeschlossene Bestellungen im Template. Der Bestellvorgang selbst ist im [Bestellablauf](/frontend/funktionsubersicht/bestellablauf) beschrieben. Der serverseitige Zugriff auf Bestellungen (z. B. für externe Systeme) erfolgt über die [API-Referenz Bestellungen](/schnittstellen/admin-interface-api/api-referenz-bestellungen), nicht über dieses Modul. *** ## Grundkonzept `$wsOrderHistory` hat keine eigenen Variablen. Sie rufen eine Methode auf, weisen das Ergebnis einer eigenen [Template-Variable](/frontend/referenz/variablen) zu und arbeiten dann mit dieser weiter. Der typische Ablauf: 1. **Liste laden**: [`loadList()`](#wsorderhistory-loadlist) gibt die Bestellungen des Kunden als Liste zurück. Das Ergebnis weisen Sie z. B. `$orderList` zu. 2. **Prüfen**: Sie prüfen mit `{{ if $orderList }}`, ob überhaupt Bestellungen vorliegen. 3. **Auflisten**: Sie iterieren über die Liste. Pro Eintrag stehen die Eckdaten (`general.orderId`, `general.dateTime`) bereit. Für Summe und Positionen laden Sie die Bestellung über ihre ID nach. 4. **Detail laden**: [`load(orderId)`](#wsorderhistory-load) lädt die vollständige Einzelbestellung (Adressen, Positionen, Preise). ### Nur für eingeloggte Kunden Beide Methoden liefern nur Daten, wenn ein Kunde angemeldet ist. Ist niemand eingeloggt, erhalten Sie eine leere Rückgabe. Prüfen Sie das Ergebnis deshalb immer mit `{{ if ... }}`, bevor Sie es ausgeben. Sonst entstehen leere Tabellen oder „tote" HTML-Strukturen. Ob ein Kunde angemeldet ist, ermitteln Sie über das [Account-Modul](/frontend/referenz/module/wsAccount). ### Liste und Einzelbestellung im Zusammenspiel * [`loadList()`](#wsorderhistory-loadlist) liefert die **Übersicht**: eine Liste der Bestellungen. Jeder Eintrag enthält die allgemeinen Eckdaten unter `general`. * [`load(orderId)`](#wsorderhistory-load) liefert die **Detailansicht** einer einzelnen Bestellung mit allen Daten: Positionen (`orderList.item`), Preise (`order`), Adressen. Der Übergang von Übersicht zu Detail läuft über die Bestell-ID: In der Liste verlinken Sie jede Bestellung mit der zugehörigen ID, auf der Zielseite lesen Sie diese ID aus dem Aufruf-Parameter und übergeben sie an `load()`. Brauchen Sie schon in der Übersicht Summe oder Positionsanzahl, rufen Sie `load()` auch dort pro Eintrag auf (siehe [Beispiele](#beispiele)). ### Seitenweises Laden (Paging) Kunden mit langer Historie können sehr viele Bestellungen haben. Statt alle auf einmal zu laden, ruft `loadList()` die Daten über den `options`-Parameter seitenweise ab (Paging). Eine „Seite" ist ein Ausschnitt der Gesamtliste. Sie geben an, welche Seite (`page`) Sie in welcher Größe (`size`) möchten, optional mit einer benannten Sortierung (`sort`). Das hält den Seitenaufbau schlank und ermöglicht eine Blätter-Navigation. Details bei der Methode [`loadList()`](#wsorderhistory-loadlist). *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsOrderHistory` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsOrderHistory | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "load": "ƒ()", "loadList": "ƒ()" } ``` Anmerkung: `"ƒ()"` kennzeichnet eine Funktion. **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ------------------- | ---------------- | -------------------------------------------------------------------- | | `loadList(options)` | array | Lädt die Bestellungen des Kunden als Liste (seitenweise/sortierbar). | | `load(orderId)` | map | Lädt eine einzelne Bestellung anhand ihrer Bestell-ID. | *** ## Templates Die Bestellhistorie lässt sich grundsätzlich in jedem Template laden, wird aber typischerweise im Konto-Bereich des Kunden eingebunden, üblicherweise im Template `account/orderHistory.htm`. Da beide Methoden nur für eingeloggte Kunden Daten liefern (siehe [Grundkonzept](#grundkonzept)), gehört die Ausgabe in einen Bereich, der ohnehin eine Anmeldung voraussetzt. *** ## Variablen `$wsOrderHistory` stellt keine eigenen Variablen bereit. Die Bestelldaten liegen in der Template-Variable, der Sie das Ergebnis von `loadList()` bzw. `load()` zuweisen (siehe [Grundkonzept](#grundkonzept)). *** ## Methoden ### \$wsOrderHistory.loadList() Gibt die Bestellungen des aktuell eingeloggten Kunden als Liste zurück, um daraus eine Bestellübersicht zu bauen. Über den optionalen Parameter `options` steuern Sie, welcher Ausschnitt geladen wird: seitenweise (`page`/`size`) und in welcher Sortierung (`sort`). **Signatur**\ `$wsOrderHistory.loadList(options)` **Rückgabe**\ `array`. Liste der Bestellungen. Jeder Eintrag trägt unter `general` die Eckdaten (`orderId`, `dateTime`). Leer, wenn kein Kunde eingeloggt ist oder keine Bestellungen vorliegen. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | --------- | ------- | ----------- | -------------------------------------------------------------------------- | | `options` | map | nein | Steuert Paging und Sortierung. Ohne Angabe wird die Standardliste geladen. | **Optionen (`options`)** | **Key** | **Typ** | **Pflicht** | **Default** | **Beschreibung** | | ------- | ------- | ----------- | ----------- | ----------------------------------------------------------------------------------------------- | | `page` | int | nein | `1` | Welche Ergebnisseite geladen wird. Zählung beginnt bei `1`. | | `size` | int | nein | - | Anzahl der Bestellungen pro Seite. | | `sort` | string | nein | - | Name einer in der Konfiguration `general.orderSortOption` definierten Sortierung (siehe unten). | Über `page` und `size` blättern Sie durch die Historie. So laden Sie die ersten 100 Bestellungen (Seite 1) bzw. die nächsten 100 (Seite 2, also Einträge 101 bis 200): ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $orderList = $wsOrderHistory.loadList({ page: 1, size: 100 }) }} {{ var $orderListPage2 = $wsOrderHistory.loadList({ page: 2, size: 100 }) }} ``` Das seitenweise Laden hält den Seitenaufbau schlank: Statt die gesamte Historie eines Kunden auf einmal zu verarbeiten, holen Sie nur den Ausschnitt, den die Seite gerade anzeigt. Pro Eintrag stehen die Eckdaten unter `general` bereit. Für Summe und Positionen laden Sie die Bestellung über `load()` nach (siehe [Beispiele](#beispiele)): ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $orderList = $wsOrderHistory.loadList({ page: 1, size: 100 }) }} {{ if $orderList }} {{ foreach $entry in $orderList }} {{= $entry.general.orderId }} – {{= $entry.general.dateTime | dateFmt("%d.%m.%Y") }} {{ /foreach }} {{ /if }} ``` Der Modifier `dateFmt` formatiert den Zeitstempel (ISO-String) in ein lesbares Datum. Der Modifier `date` darf hier nicht verwendet werden. Er bricht das Rendering ab. **Sortierung über `sort`** Der Wert von `sort` ist kein freier Feldname, sondern der Name einer vorab definierten Sortier-Option. Diese legen Sie zuerst in der Konfiguration unter [`general.orderSortOption`](/konfiguration/general-allgemeine-shopeinstellungen) an. So sind nur freigegebene, benannte Sortierungen möglich. Das verhindert beliebige Sortierfelder und bündelt die erlaubten Sortierungen zentral. Eine Sortier-Option hat folgende Felder: | **Key** | **Typ** | **Beschreibung** | | ----------- | ------- | --------------------------------------------------------------------------------- | | `name` | string | Eindeutiger Name, den Sie anschließend in `loadList({ sort: "" })` angeben. | | `fieldName` | string | Feld, nach dem sortiert wird (z. B. `createdAt`). | | `direction` | string | Sortierrichtung: `asc` (aufsteigend) oder `desc` (absteigend). | Beispiel-Konfiguration für „neueste zuerst": ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "direction": "desc", "fieldName": "createdAt", "name": "dateDesc" } ``` Anschließend referenzieren Sie diese Sortierung im Template über ihren Namen. Damit liefert `loadList()` die 100 neuesten Bestellungen zuerst: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $orderList = $wsOrderHistory.loadList({ page: 1, size: 100, sort: "dateDesc" }) }} ``` ### \$wsOrderHistory.load() Gibt eine einzelne Bestellung anhand ihrer Bestell-ID als Map mit allen Bestelldaten zurück (z. B. für eine Detailansicht oder eine Nachbestellung). **Signatur**\ `$wsOrderHistory.load(orderId)` **Rückgabe**\ `map`- Bestelldaten der angeforderten Bestellung. Leer, wenn kein Kunde eingeloggt ist oder die ID nicht zu einer Bestellung des Kunden gehört. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | --------- | ------- | ----------- | ------------------------------------------- | | `orderId` | string | ja | ID der Bestellung, die geladen werden soll. | ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $order = $wsOrderHistory.load("48") }} {{ if $order }} Bestellung {{= $order.general.orderId }} vom {{= $order.general.dateTime | dateFmt("%d.%m.%Y") }} {{ /if }} ``` #### Struktur der Bestell-Map Die Rückgabe von `load()` ist nach Themen in Unter-Maps gegliedert. Weisen Sie das Ergebnis zunächst einer Variable zu (im Folgenden `$order`) und greifen Sie darüber auf die einzelnen Bereiche zu. **JSON-Struktur (Überblick):** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "general": { "orderId": "...", "dateTime": "...", "shopId": "...", "subshopId": "...", "sessionId": "...", "shopLanguage": "...", "testMode": true }, "order": { "priceType": "...", "currencyIso": "...", "currencySymbol": "...", "defaultTaxRate": "...", "paymentId": "...", "paymentOrderText": "...", "delivererId": "...", "delivererOrderText": "...", "deliveryCost": "...", "deliveryTaxRate": "...", "subtotal": "...", "total": "...", "tax": "...", "totalDiscount": "..." }, "customer": { "accountType": "...", "accountId": "...", "email": "...", "ipAddress": "..." }, "orderList": { "item": [ { "productId": "..." } ] }, "billAddress": {}, "shippingAddress":{}, "freeFields": {}, "deliveryStatus": {} } ``` `general` enthält die allgemeinen Eckdaten der Bestellung: | **Key** | **Typ** | **Beschreibung** | | -------------- | ------- | -------------------------------------------------------- | | `orderId` | string | ID der Bestellung. | | `dateTime` | string | Datum und Uhrzeit der Bestellung (ISO-String). | | `shopId` | string | ID des Shops, in dem die Bestellung getätigt wurde. | | `subshopId` | string | ID des Subshops, in dem die Bestellung aufgegeben wurde. | | `sessionId` | string | ID der Session, in der die Bestellung aufgegeben wurde. | | `shopLanguage` | string | Sprache des Shops zum Bestellzeitpunkt. | | `testMode` | bool | `true`, wenn die Bestellung im Testmodus erfolgte. | `order` enthält Preise, Zahlungs- und Versandart: | **Key** | **Typ** | **Beschreibung** | | -------------------- | ------- | -------------------------------------------------- | | `priceType` | string | Preistyp: `"net"` (netto) oder `"gross"` (brutto). | | `currencyIso` | string | ISO-Code der Währung (z. B. `"EUR"`). | | `currencySymbol` | string | Währungssymbol (z. B. `"€"`). | | `defaultTaxRate` | string | Standard-Steuersatz. | | `paymentId` | string | ID der Zahlungsart. | | `paymentOrderText` | string | Beschreibung der Zahlungsart. | | `delivererId` | string | ID der Versandart. | | `delivererOrderText` | string | Beschreibung der Versandart. | | `deliveryCost` | string | Versandkosten. | | `deliveryTaxRate` | string | Steuersatz der Versandkosten. | | `subtotal` | string | Warenwert (Summe der Positionen). | | `total` | string | Gesamtpreis der Bestellung. | | `tax` | string | Gesamte Steuern der Bestellung. | | `totalDiscount` | string | Gesamter Rabatt der Bestellung. | `customer` enthält die Daten zum Besteller: | **Key** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------ | | `accountType` | string | Kontotyp: `"Gast"` oder `"Bestandskunde"`. | | `accountId` | string | ID des Accounts. | | `email` | string | E-Mail-Adresse des Bestellers. | | `ipAddress` | string | IP-Adresse zum Bestellzeitpunkt. | Weitere Bereiche: | **Key** | **Typ** | **Beschreibung** | | ----------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `orderList` | map | Enthält unter `item` die bestellten Positionen. | | `orderList.item` | array | Liste der bestellten Positionen. Jeder Eintrag trägt mindestens `productId` (über [`$wsProducts.load()`](/frontend/referenz/module/wsproducts) ladbar). | | `billAddress` | map | Rechnungsadresse. | | `shippingAddress` | map | Lieferadresse. | | `freeFields` | map | Freie Felder, die bei der Bestellung erfasst wurden. | | `deliveryStatus` | map | Lieferstatus der Bestellung (Tracking-Daten oder manueller Statustext). Nur vorhanden, wenn im Admin Interface ein Lieferstatus gesetzt wurde. Details siehe [Lieferstatus (`deliveryStatus`)](#lieferstatus-deliverystatus). | #### Lieferstatus (`deliveryStatus`) Der Bereich `deliveryStatus` enthält den Lieferstatus der Bestellung. Er ist nur vorhanden, wenn im Admin Interface ein Lieferstatus für die Bestellung gesetzt wurde. Prüfen Sie das Feld deshalb immer mit `{{ if $order.deliveryStatus }}`, bevor Sie es ausgeben. Der Lieferstatus wird im Admin Interface unter Bestellungen gepflegt und in zwei Arten unterschieden: **Geltungsbereich** (`type`): * `global` - Der Status gilt für die gesamte Bestellung (alle Produkte werden in einem Paket geliefert). * `splitted` - Die Bestellung wird in mehreren Paketen geliefert; jedes Paket trägt einen eigenen Status und eine Liste der enthaltenen Positionen. **Status-Art** (bei `global`: `statusType`, bei `splitted` je Paket: `deliveryStatusType`): * `tracking` - Es wurden eine Sendungsnummer (`trackingNumber`) und ein Versanddienstleister (`trackingVendorId`) hinterlegt. `trackingVendorId` entspricht der `id` der Konfiguration [checkout.shipTrack](/konfiguration/checkout-bestellablauf#checkout-shiptrack-paketverfolgung). * `manual` - Ein frei formulierter Statustext wurde im Admin Interface eingetragen. `deliveryStatus` wird nur von [`load()`](#wsorderhistory-load) geliefert. Die Einträge aus [`loadList()`](#wsorderhistory-loadlist) enthalten das Feld nicht - laden Sie die Bestellung bei Bedarf über ihre ID nach. Struktur bei globalem Status mit Tracking-Daten: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "deliveryStatus": { "type": "global", "statusType": "tracking", "data": { "trackingNumber": "5586666654788855", "trackingVendorId": "dhl" } } } ``` Struktur bei globalem manuellem Status: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "deliveryStatus": { "type": "global", "statusType": "manual", "data": { "status": "Wird kommissioniert" } } } ``` Struktur bei Lieferung in mehreren Paketen (`splitted`): ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "deliveryStatus": { "type": "splitted", "packages": [ { "deliveryStatusType": "tracking", "data": { "trackingNumber": "5586666654788855", "trackingVendorId": "dhl" }, "items": [ { "basketId": "62e484ee2283dcab7c14", "productId": "237-53337", "name": "NextGen X562", "quantity": "1.00" } ] } ] } } ``` Felder in der Übersicht: | **Key** | **Typ** | **Beschreibung** | | --------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------- | | `type` | string | Geltungsbereich des Status: `global` (gesamte Bestellung) oder `splitted` (pro Paket). | | `statusType` | string | Nur bei `type: "global"`: Art des Status - `tracking` oder `manual`. | | `data` | map | Nur bei `type: "global"`: die Statusdaten (siehe unten). | | `data.trackingNumber` | string | Sendungsnummer des Versanddienstleisters (bei `tracking`). | | `data.trackingVendorId` | string | ID der [checkout.shipTrack](/konfiguration/checkout-bestellablauf#checkout-shiptrack-paketverfolgung)-Konfiguration (bei `tracking`). | | `data.status` | string | Manuell eingetragener Statustext (bei `manual`). | | `packages` | array | Nur bei `type: "splitted"`: Liste der Pakete. | | `packages[$i].deliveryStatusType` | string | Art des Status dieses Pakets: `tracking` oder `manual`. | | `packages[$i].data` | map | Statusdaten des Pakets (Felder wie oben; bei `manual` heißt das Feld hier `manualStatus`). | | `packages[$i].items` | array | Positionen der Bestellung, die in diesem Paket enthalten sind (u.a. `basketId`, `productId`). | **Beispiel** \ Lieferstatus einer Bestellung anzeigen. Vor der Anzeige wird über [`$wsShipTrack.zipCodeConfirmed()`](/frontend/referenz/module/wsshiptrack#wsshiptrack-zipcodeconfirmed) geprüft, ob der Kunde die Postleitzahl der Bestellung bestätigt hat; falls nicht, wird das Bestätigungsformular der Aktion `ConfirmZipCode` angezeigt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $order = $wsOrderHistory.load($wsViews.current.params.orderHistorySelect) }} {{ if $order.deliveryStatus }} {{ if $wsShipTrack.zipCodeConfirmed($order.general.orderId) }} {{ if $order.deliveryStatus.type == 'global' }} {{# Lieferstatus für die gesamte Bestellung #}} {{ if $order.deliveryStatus.statusType == 'manual' }}

    Lieferstatus: {{= $order.deliveryStatus.data.status }}

    {{ /if }} {{ if $order.deliveryStatus.statusType == 'tracking' }}

    Sendungsnummer: {{= $order.deliveryStatus.data.trackingNumber }}

    Versanddienstleister: {{= $order.deliveryStatus.data.trackingVendorId }}

    {{ /if }} {{ /if }} {{ if $order.deliveryStatus.type == 'splitted' }} {{# Lieferstatus je Paket #}} {{ foreach $package in $order.deliveryStatus.packages }} {{ if $package.deliveryStatusType == 'manual' }}

    Lieferstatus: {{= $package.data.manualStatus }}

    {{ /if }} {{ if $package.deliveryStatusType == 'tracking' }}

    Sendungsnummer: {{= $package.data.trackingNumber }}

    Versanddienstleister: {{= $package.data.trackingVendorId }}

    {{ /if }} {{ foreach $packageItem in $package.items }}

    {{= $packageItem.name }} ({{= $packageItem.quantity }} Stück)

    {{ /foreach }} {{ /foreach }} {{ /if }} {{ else }} {{# PLZ noch nicht bestätigt: Formular zur Bestätigung anzeigen #}} {{ var $actionConfirmZipCode = $wsActions.create('ConfirmZipCode') }}

    Bitte bestätigen Sie die Postleitzahl der Lieferadresse, um den Lieferstatus zu sehen:

    {{ /if }} {{ /if }} ``` **Ergebnis**\ Ist der Lieferstatus gesetzt und die Postleitzahl bestätigt, wird je nach Konfiguration der manuelle Statustext oder die Tracking-Information angezeigt - bei Paket-Lieferung pro Paket inklusive der enthaltenen Positionen. Solange die Postleitzahl nicht bestätigt ist, erscheint stattdessen das Bestätigungsformular. *** ## Aktionen Für `$wsOrderHistory` stehen keine Aktionen zur Verfügung. Für die Bestätigung der Postleitzahl vor Anzeige des Lieferstatus siehe die Aktion `ConfirmZipCode` des Moduls [\$wsShipTrack](/frontend/referenz/module/wsshiptrack). *** ## Beispiele ### Bestellübersicht mit Summe und Positionsanzahl Lädt die Bestellliste, iteriert über die Einträge und lädt pro Eintrag die vollständige Bestellung nach, um Gesamtpreis (`order.total`) und Anzahl der Positionen (`len(orderList.item)`) anzuzeigen. Jede Zeile verlinkt über `viewUrl()` auf die Detailansicht und hängt die Bestell-ID als Parameter `orderHistorySelect` an. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $orderList = $wsOrderHistory.loadList() }} {{ if $orderList }} {{ foreach $entry in $orderList }} {{ var $order = $wsOrderHistory.load($entry.general.orderId) }} {{ if $order }} {{= $entry.general.dateTime | dateFmt("%d.%m.%Y") }} – {{= len($order.orderList.item) }} Position(en) – {{= $order.order.total | currency }} {{ /if }} {{ /foreach }} {{ else }}

    Es liegen keine Bestellungen vor.

    {{ /if }} ``` **Ergebnis** \ Pro Bestellung eine verlinkte Zeile mit Datum, Positionsanzahl und Gesamtpreis. Der Modifier `currency` gibt das Währungssymbol bereits mit aus (kein separates `currencySymbol` nötig). Ist der Kunde nicht eingeloggt oder hat keine Bestellungen, erscheint der Hinweistext. ### Eine Bestellung aus der Liste öffnen (Detailansicht) Schließt den Loop: Die Detailansicht liest die in der Übersicht angehängte Bestell-ID aus dem URL-Parameter, lädt damit die Einzelbestellung und gibt deren Eckdaten samt Positionen aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsViews.current.params.orderHistorySelect }} {{ var $order = $wsOrderHistory.load($wsViews.current.params.orderHistorySelect) }} {{ if $order }}

    Bestellung {{= $order.general.orderId }}

    Datum: {{= $order.general.dateTime | dateFmt("%d.%m.%Y") }}

    Gesamtpreis: {{= $order.order.total | currency }}

    Zahlungsart: {{= $order.order.paymentOrderText }}

    Versandart: {{= $order.order.delivererOrderText }}

    {{ foreach $position in $order.orderList.item }} {{ var $product = $wsProducts.load($position.productId) }} {{ if $product }}

    {{= $product.name }}

    {{ /if }} {{ /foreach }} {{ /if }} {{ /if }} ``` **Ergebnis** \ Klickt der Kunde in der Übersicht auf eine Bestellung, wird die Seite mit `?wsvc=View&orderHistorySelect=` neu aufgebaut, die Bestellung geladen und mit ihren Positionen angezeigt. Jede Position wird über ihre `productId` mit `$wsProducts.load()` zum vollständigen Produkt aufgelöst. ### Seitenweise durch viele Bestellungen blättern Über `page` blättern Sie durch lange Historien. Die anzuzeigende Seitennummer holen Sie aus einem URL-Parameter, sodass ein „Weiter"-Link jeweils einen neuen Seitenaufbau mit der nächsten Seite auslöst. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $page = $wsViews.current.params.orderPage }} {{ if not $page }}{{ var $page = 1 }}{{ /if }} {{ var $orderList = $wsOrderHistory.loadList({ page: $page, size: 20 }) }} {{ if $orderList }} {{ foreach $entry in $orderList }}

    {{= $entry.general.orderId }} – {{= $entry.general.dateTime | dateFmt("%d.%m.%Y") }}

    {{ /foreach }} Nächste Seite {{ /if }} ``` **Ergebnis** \ Pro Seitenaufruf werden 20 Bestellungen angezeigt. Der Link lädt jeweils die nächsten 20. ### Nach Datum sortieren (neueste zuerst) Setzt die in der Konfiguration `general.orderSortOption` angelegte Sortier-Option `dateDesc` voraus (siehe [`loadList()`](#wsorderhistory-loadlist)). Damit liefert `loadList()` die neuesten Bestellungen zuerst. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $orderList = $wsOrderHistory.loadList({ page: 1, size: 100, sort: "dateDesc" }) }} {{ if $orderList }} {{ foreach $entry in $orderList }}

    {{= $entry.general.dateTime | dateFmt("%d.%m.%Y") }} – {{= $entry.general.orderId }}

    {{ /foreach }} {{ /if }} ``` **Ergebnis** \ Die 100 neuesten Bestellungen, absteigend nach Bestelldatum sortiert. *** ## Weiterführende Links * [\$wsAccount - Account & Adressdaten](/frontend/referenz/module/wsAccount): um zu prüfen, ob ein Kunde eingeloggt ist, bevor Sie die Historie laden. * [\$wsViews - Aktuelle Informationen abrufen](/frontend/referenz/module/wsviews): liefert `viewUrl()` für die Detail-Verlinkung und `current.params` zum Auslesen des Parameters `orderHistorySelect`. * [\$wsProducts - Produktdaten](/frontend/referenz/module/wsproducts): lädt zu einer `productId` aus `orderList.item` das vollständige Produkt (Name, Bilder). * [\$wsShipTrack - Sendungsverfolgung](/frontend/referenz/module/wsshiptrack): lädt zu einer Sendungsnummer aus `deliveryStatus` die Tracking-Informationen des Versanddienstleisters und prüft die PLZ-Bestätigung. * [general - Allgemeine Shopeinstellungen](/konfiguration/general-allgemeine-shopeinstellungen): hier soll unter `orderSortOption` die für `sort` vorgesehene Sortier-Option angelegt werden (siehe Hinweis bei `loadList()`). * [Bestellablauf](/frontend/funktionsubersicht/bestellablauf): beschreibt, wie eine Bestellung entsteht (Abgrenzung zu dieser Seite). # $wsPayPalCheckout - PayPal Source: https://dokumentation.websale.de/frontend/referenz/module/wspaypalcheckout Modul $wsPayPalCheckout: PayPal Express Checkout, Google Pay und Apple Pay im Frontend einbinden und den aktuellen Zahlungsstatus auswerten. Mit dem `$wsPayPalCheckout` Modul können Sie PayPal-Zahlungsdaten dynamisch im Frontend verwenden. Es unterstützt verschiedene Zahlungsmethoden wie PayPal Express Checkout, Google Pay und Apple Pay. In diesem Abschnitt erfahren Sie, wie Sie den Zahlungsstatus abfragen und die Payment-Daten für die Integration nutzen können. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsPayPalCheckout` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsPayPalCheckout | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "integrationDate": "...", "status": "...", "paymentCanceled": false, "paymentFailed": false, "paymentDeclined": false, "expressCheckout": false, "expressCheckoutGooglePay": false, "expressCheckoutApplePay": false, "googlePay": { "paymentData": "...", "transactionInfo": { "countryCode": "...", "currencyCode": "...", "displayItems": [...], "totalPrice": "...", "totalPriceLabel": "...", "totalPriceStatus": "..." } }, "applePay": { "billingContact": { }, "brandName": "...", "payLineItems": [...], "paymentData": "...", "shippingOptions": [...] }, "loadData": "ƒ()", "loadConfigData": "ƒ()" } ``` **Anmerkung:** `ƒ()` kennzeichnet eine Funktion. **Variablen und Methoden in der Übersicht** | **Variable** | **Rückgabe-Typ** | **Beschreibung** | | -------------------------- | ---------------- | ----------------------------------------------------------------------------------- | | `integrationDate` | string | Gibt das PayPal Checkout Integrationsdatum aus. | | `status` | string | Gibt den aktuellen Payment-Status der Session aus. | | `paymentCanceled` | bool | Gibt an, ob die Zahlung abgebrochen wurde. | | `paymentFailed` | bool | Gibt an, ob die Zahlung fehlgeschlagen ist. | | `paymentDeclined` | bool | Gibt an, ob die Zahlung abgelehnt wurde. | | `expressCheckout` | bool | Gibt an, ob PayPal Express Checkout möglich ist. | | `expressCheckoutGooglePay` | bool | Gibt an, ob Google Pay Express möglich ist. | | `expressCheckoutApplePay` | bool | Gibt an, ob Apple Pay Express möglich ist. | | `googlePay` | map | Gibt Google-Pay-spezifische Daten aus. | | `applePay` | map | Gibt Apple-Pay-spezifische Daten aus. | | `loadData()` | map | Lädt alle Payment-Daten für PayPal Checkout. | | `loadConfigData()` | map | Lädt die Konfigurationsdaten des PayPal Checkout, ohne Prüfung des Bestellkontexts. | *** ## Templates Das \$wsPayPalCheckout Modul wird typischerweise im Checkout-Bereich verwendet, insbesondere auf der Zahlungsseite und der Bestellbestätigung. Die PayPal-Buttons können auch auf Produktseiten oder im Warenkorb für Express-Checkout eingebunden werden. *** ## Variablen ### \$wsPayPalCheckout.integrationDate Gibt das Integrationsdatum der PayPal-Anbindung aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Integrationsdatum: {{= $wsPayPalCheckout.integrationDate }} ``` ### \$wsPayPalCheckout.status Gibt den Status der PayPal-Zahlung aus(leer, wenn kein Zahlungsvorgang aktiv). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Status: {{= $wsPayPalCheckout.status }} ``` ### \$wsPayPalCheckout.paymentCanceled Gibt `true` aus, wenn der Kunde die Zahlung abgebrochen hat. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsPayPalCheckout.paymentCanceled }} // Zahlung wurde abgebrochen {{ /if }} ``` ### \$wsPayPalCheckout.paymentFailed Gibt `true` aus, wenn ein technischer Fehler bei der Zahlung aufgetreten ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsPayPalCheckout.paymentFailed }} // Zahlung ist fehlgeschlagen {{ /if }} ``` ### \$wsPayPalCheckout.paymentDeclined Gibt `true` aus, wenn die Zahlung von PayPal oder der Bank abgelehnt wurde. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsPayPalCheckout.paymentDeclined }} // Zahlung wurde abgelehnt {{ /if }} ``` ### \$wsPayPalCheckout.expressCheckout Gibt an, ob PayPal Express Checkout möglich ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsPayPalCheckout.expressCheckout }} // PayPal Express Checkout anzeigen {{ /if }} ``` ### \$wsPayPalCheckout.expressCheckoutGooglePay Gibt an, ob Google Pay Express möglich ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsPayPalCheckout.expressCheckoutGooglePay }} // Google Pay anzeigen {{ /if }} ``` ### \$wsPayPalCheckout.expressCheckoutApplePay Gibt an, ob Apple Pay Express möglich ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsPayPalCheckout.expressCheckoutApplePay }} // Apple Pay anzeigen {{ /if }} ``` ### \$wsPayPalCheckout.googlePay Gibt eine Map mit Google Pay spezifischen Inhalten aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Google-Pay-Daten: {{= $wsPayPalCheckout.googlePay }} ``` ### \$wsPayPalCheckout.applePay Gibt eine Map mit Apple Pay spezifischen Daten aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Apple-Pay-Daten: {{= $wsPayPalCheckout.applePay }} ``` *** ## Methoden ### \$wsPayPalCheckout.loadData() Lädt alle Payment-Daten für PayPal Checkout. Gibt `null` zurück, wenn kein aktiver Zahlungsvorgang vorhanden ist. **Signatur**
    `$wsPayPalCheckout.loadData(expressCheckout)` **Rückgabe**
    `Map` - Map mit Payment-Daten oder `null`. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------------- | ------- | ----------- | ---------------------------------------------- | | `expressCheckout` | bool | nein | `true` lädt zusätzlich Express-Checkout-Daten. | **Beispiel,** das die Payment-Daten lädt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myPaypalDataVariable = $wsPayPalCheckout.loadData() }} {{ if $myPaypalDataVariable }} // Payment-Daten verfügbar {{ /if }} ``` Mit Verwendung der Funktion `$wsPayPalCheckout.loadData()` stehen verschiedene Variablen zur Verfügung, um Payment-Daten abzurufen und auszugeben. Nachfolgend eine Übersicht, welche Variablen verfügbar sind. ### Payment-Daten (Rückgabe von `$wsPayPalCheckout.loadData()` ) Zunächst ist es notwendig, die Map mit den Payment-Daten, wie im obigen Beispiel dargestellt, einer lokalen Variable zuzuweisen. Diese kann anschließend an verschiedenen Stellen im Template verwendet werden. **JSON-Ausgabe der Variablen** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "sandbox": true/false, "merchantId": "...", "payerId": "...", "clientId": "...", "paymentType": "paypal", "languageCode": "...", "intent": "capture", "approvalUrl": "...", "cancelUrl": "...", "errorUrl": "...", "expressApprovalUrl": "...", "getClientToken": "ƒ()", "orderId": "...", "googlePay": { ... }, "applePay": { ... } } ``` **Variablen in der Übersicht** Allgemeine Eigenschaften: | **Variable** | **Typ** | **Beschreibung** | | -------------------- | -------- | ------------------------------------------------------------------------- | | `sandbox` | bool | Gibt an, ob der Sandbox-Modus (Testmodus für Zahlungsarten) aktiv ist. | | `merchantId` | string | PayPal Merchant-ID. | | `payerId` | string | PayPal Payer-ID. | | `clientId` | string | PayPal Client-ID. | | `paymentType` | string | Zahlungstyp (Standard: “`paypal`”). | | `languageCode` | string | Sprachcode. | | `approvalUrl` | string | URL für die Payment-Bestätigung. | | `cancelUrl` | string | URL bei Abbruch der Zahlung. | | `errorUrl` | string | URL bei aufgetretenen Fehlern. | | `expressApprovalUrl` | string | URL bei erfolgreicher Express-Zahlung. | | `getClientToken` | function | Funktion, die den Client-Token für die PayPal-SDK-Integration zurückgibt. | | `orderId` | string | PayPal Order-ID der aktuellen Transaktion. | **Eigenschaften von** **Google Pay und Apple Pay** Google Pay: | **Variable** | **Typ** | **Beschreibung** | | ----------------- | ------- | -------------------------------------------- | | `paymentData` | string | Antwortdaten von Google Pay (unverarbeitet). | | `transactionInfo` | map | Map mit Transaktionsinfos von Google Pay. | Apple Pay: | **Variable** | **Typ** | **Beschreibung** | | ----------------- | ------- | ------------------------------------------- | | `shippingOptions` | array | Versandoptionen. | | `billingContact` | map | Rechnungsadresse. | | `payLineItems` | array | Apple Pay Positionen. | | `brandName` | string | Markenname. | | `paymentData` | string | Antwortdaten von Apple Pay (unverarbeitet). | ### \$wsPayPalCheckout.loadConfigData() Lädt die Konfigurationsdaten des PayPal Checkout SDK-Parameter wie Client-ID, Sprachcode und Modus. Diese Methode ist das Gegenstück zu `loadData()` für Seiten außerhalb des Bestellvorgangs, etwa eine Seite im Kundenkonto, auf der der Kunde sein Konto mit dem Zahlungsanbieter verknüpft. Es gibt zwei Unterschiede zu `loadData()` : 1. Das zurückgegebene Objekt enthält weniger Informationen, weil die bestellbezogenen Werte `approvalUrl` , `cancelUrl` , `errorUrl` , `expressApprovalUrl` und `orderId` fehlen. 2. Es wird nicht geprüft, ob im Checkout eine PayPal-Zahlungsart gewählt ist oder ob sich Produkte im Warenkorb befinden. Deshalb liefert `loadConfigData()` nie `null` zurück, während `loadData()` außerhalb eines aktiven Zahlungsvorgangs null liefert. **Signatur**
    `$wsPayPalCheckout.loadConfigData(paymentId)` **Rückgabe**
    `Map` - Map mit den Konfigurationsdaten. Nie `null`. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `paymentId` | string | nein | ID der Zahlungsart, deren Einstellungen gelesen werden sollen. Ohne Angabe werden die Werte aus der allgemeinen PayPal-Checkout-Konfiguration gelesen. | **Beispiel,** das die Konfigurationsdaten für die Einbindung des PayPal-SDK lädt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $ppcConfig = $wsPayPalCheckout.loadConfigData() }} ``` Mit Verwendung der Funktion `$wsPayPalCheckout.loadConfigData()` stehen verschiedene Variablen zur Verfügung, um die Konfigurationsdaten abzurufen und auszugeben. Nachfolgend eine Übersicht, welche Variablen verfügbar sind. ### Konfigurationsdaten (Rückgabe von \$wsPayPalCheckout.loadConfigData() ) Zunächst ist es notwendig, die Map mit den Konfigurationsdaten, wie im obigen Beispiel dargestellt, einer lokalen Variable zuzuweisen. Anschließend kann diese an verschiedenen Stellen im Template verwendet werden. **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "sandbox": true/false, "merchantId": "...", "payerId": "...", "clientId": "...", "paymentType": "paypal", "languageCode": "...", "intent": "capture", "getClientToken": "ƒ()" } ``` **Variablen in der Übersicht** | **Variable** | **Typ** | **Beschreibung** | | ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `sandbox` | bool | Gibt an, ob der Sandbox-Modus (Testmodus für Zahlungsarten) aktiv ist. | | `merchantId` | string | PayPal Merchant-ID des Händlerkontos (identisch mit `payerId`, entspricht [`payment.payPalCheckout.payerId`](/konfiguration/payment-zahlungsmethoden#payment-paypalcheckout-paypal-checkout-konfiguration)). | | `payerId` | string | PayPal Merchant-ID des Händlerkontos (identisch mit `merchantId`). Beide Namen werden geliefert, weil das PayPal-SDK den Wert je nach Kontext unter dem einen oder dem anderen Namen erwartet. | | `clientId` | string | PayPal Client-ID. Je nach Modus wird die Live- oder die Sandbox-Client-ID geliefert. | | `paymentType` | string | Zahlungstyp (Default: "`paypal`"). | | `languageCode` | string | Sprachcode. | | `intent` | string | PayPal-Intent der Transaktion für den SDK-Parameter `intent`. Derzeit immer `"capture"`. | | `getClientToken` | function | Funktion, die das Client-Token für die Einbindung des PayPal-SDK zurückgibt (`null`, wenn kein Token ermittelt werden kann). | `getClientToken()` ermittelt das Token immer für die im Checkout gewählte Zahlungsart, unabhängig davon, welche `paymentId` an `loadConfigData()` übergeben wurde. *** ## Aktionen Für `$wsPayPalCheckout` stehen keine Aktionen zur Verfügung. *** ## Weiterführende Links * [\$wsCheckout](/frontend/referenz/module/wscheckout) # $wsProductRating - Produktbewertungen Source: https://dokumentation.websale.de/frontend/referenz/module/wsproductrating Modul $wsProductRating: Produktbewertungen laden, Durchschnittswerte prüfen und im Frontend als Vertrauensindikator für Kunden darstellen. Mit dem `$wsProductRating` Modul können Sie Produktbewertungen laden, prüfen und im Frontend anzeigen. Produktbewertungen sind ein wichtiges Element für Kaufentscheidungen. Sie zeigen Kunden die Erfahrungen anderer Käufer und erhöhen das Vertrauen in Produkte. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsProductRating` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsProductRating | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "checkRatingExistence": "ƒ()", "loadAllProductRatings": "ƒ()", "loadLatestRatingForAccount": "ƒ()", "loadRatingByAccount": "ƒ()", "loadRatingStatistics": "ƒ()", "loadSingleRating": "ƒ()" } ``` Anmerkung: `“ƒ()”` kennzeichnet eine Funktion. **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ------------------------- | ---------------- | -------------------------------------------------------------------------------------- | | `checkRatingExistence()` | bool | Prüft, ob für ein Produkt in Verbindung mit einer Bestellung eine Bewertung existiert. | | `loadAllProductRatings()` | array | Lädt alle Bewertungen eines Produkts. | | `loadRatingStatistics()` | map | Lädt Statistiken zu den Bewertungen eines Produkts. | | `loadSingleRating()` | map | Lädt eine einzelne Bewertung anhand von Produkt- und Bestell-ID. | | `loadLatestRating()` | map | Lädt die neueste Bewertung des aktuell eingeloggten Kunden. | | `loadRatingByAccount()` | map | Lädt eine Produktbewertung des aktuell eingeloggten Kunden. | *** ## Templates Produktbewertungen werden typischerweise auf der Produktdetailseite (product.htm) angezeigt. Sie können aber auch auf Kategorieseiten oder in der Bestellhistorie eingebunden werden, um Kunden zur Bewertung aufzufordern. *** ## Variablen Für `$wsProductRating` stehen keine Variablen zur Verfügung. *** ## Methoden ### \$wsProductRating.checkRatingExistence() Prüft, ob für ein Produkt in Verbindung mit einer Bestellung bereits eine Bewertung existiert. **Signatur**\ `$wsProductRating.checkRatingExistence(productId, orderId)` **Rückgabe**\ `bool` - `true` wenn eine Bewertung existiert, sonst `false`. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | ------------------ | | `productId` | string | ja | ID des Produkts. | | `orderId` | string | ja | ID der Bestellung. | **Beispiel,** das prüft ob eine Bewertung existiert. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsProductRating.checkRatingExistence(productId, orderId) }} // Bewertung vorhanden {{ /if }} ``` ### \$wsProductRating.loadAllProductRatings() Lädt alle Bewertungen eines Produkts. **Signatur**\ `$wsProductRating.loadAllProductRatings(productId)` **Rückgabe**\ `array` - Liste mit allen Bewertungen des Produkts. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | ---------------- | | `productId` | string | ja | ID des Produkts. | **Beispiel,** das alle Bewertungen eines Produkts lädt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProductRatings = $wsProductRating.loadAllProductRatings(productId) }} ``` ### \$wsProductRating.loadRatingStatistics() Lädt Statistiken zu den Bewertungen eines Produkts. **Signatur**\ `$wsProductRating.loadRatingStatistics(productId)` **Rückgabe**\ `map` - Map mit Bewertungsstatistiken (z.B. Durchschnitt, Anzahl). **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | ---------------- | | `productId` | string | ja | ID des Produkts. | **Beispiel,** das die Statistik eines Produkts lädt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myRatingStatistics = $wsProductRating.loadRatingStatistics(productId) }} ``` ### \$wsProductRating.loadSingleRating() Lädt eine einzelne Bewertung anhand von Produkt- und Bestell-ID. **Signatur**\ `$wsProductRating.loadSingleRating(productId, orderId)` **Rückgabe**\ `map` - Map mit den Bewertungsdaten. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | ------------------ | | `productId` | string | ja | ID des Produkts. | | `orderId` | string | ja | ID der Bestellung. | **Beispiel, das eine einzelne Bewertung lädt.** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myRating = $wsProductRating.loadSingleRating(productId, orderId) }} ``` ### \$wsProductRating.loadLatestRatingForAccount() Lädt die neueste Bewertung des aktuell eingeloggten Kunden. **Signatur**\ `$wsProductRating.loadLatestRatingForAccount()` **Rückgabe**\ `map` - Map mit den Bewertungsdaten. **Beispiel,** das die neueste Bewertung des Kunden lädt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myLatestRating = $wsProductRating.loadLatestRatingForAccount() }} ``` ### \$wsProductRating.loadRatingByAccount() Lädt eine Produktbewertung des aktuell eingeloggten Kunden. **Signatur**\ `$wsProductRating.loadRatingByAccount(productId)` **Rückgabe**\ `map` - Map mit den Bewertungsdaten des Kunden. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | ---------------- | | `productId` | string | ja | ID des Produkts. | **Beispiel,** das die Bewertung des Kunden für ein Produkt lädt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProductRating = $wsProductRating.loadRatingByAccount(productId) }} ``` *** ## Aktionen Für `$wsProductRating` sind keine Aktionen vorhanden. *** ## Beispiele ### Durchschnittsbewertung anzeigen In diesem Beispiel wird die Durchschnittsbewertung und die Anzahl der Bewertungen eines Produkts angezeigt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $statistics = $wsProductRating.loadRatingStatistics($product.id) }} {{ if $statistics.totalCount > 0 }} Bewertung: {{= $statistics.averageRating }} / 5 ({{= $statistics.totalCount }} Bewertungen) {{ /if }} ``` ### Alle Bewertungen eines Produkts auflisten In diesem Beispiel werden alle Bewertungen eines Produkts geladen und angezeigt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $ratings = $wsProductRating.loadAllProductRatings($product.id) }} {{ if $ratings }} {{ foreach $rating in $ratings }}

    {{= $rating.author }}: {{= $rating.rating }} Sterne

    {{= $rating.text }}

    {{ /foreach }} {{ else }}

    Noch keine Bewertungen vorhanden.

    {{ /if }} ``` ### Prüfen, ob Kunde bereits bewertet hat In diesem Beispiel wird geprüft, ob der Kunde ein Produkt bereits bewertet hat, bevor das Bewertungsformular angezeigt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if !$wsProductRating.checkRatingExistence($product.id, $order.id) }} {{ else }}

    Sie haben dieses Produkt bereits bewertet.

    {{ /if }} ``` *** ## Weiterführende Links * [Storefront API Kundenbewertungen](/schnittstellen/storefront-api/storefront-api-kundenbewertungen) # $wsProducts - Produktdaten Source: https://dokumentation.websale.de/frontend/referenz/module/wsproducts Modul $wsProducts: Produktdaten dynamisch laden und im Frontend anzeigen. Einzelprodukte, Listen, Preise, Aktionspreise, Bilder und Beschreibungen ausgeben. Mit dem `$wsProducts` Modul können Sie Produktdaten dynamisch im Frontend laden und anzeigen. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsProducts` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsProducts | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "load": "ƒ()", "loadByNumber": "ƒ()", "loadByCustomNumber": "ƒ()", "variantInfo": "ƒ()" } ``` **Anmerkung:** `ƒ()` kennzeichnet eine Funktion. **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ---------------------- | ---------------- | ---------------------------------------------------------------- | | `load()` | map | Gibt ein Produkt anhand der Produkt-ID zurück. | | `loadByNumber()` | map | Gibt ein Produkt anhand der Artikelnummer zurück. | | `loadByCustomNumber()` | map | Gibt ein Produkt anhand einer benutzerdefinierten Nummer zurück. | | `variantInfo()` | map | Liefert die Varianten-Daten zu einem Produkt zurück. | *** ## Templates Standardmäßig werden Produkte über das Template `product.htm` angezeigt. Dieses befindet sich im Verzeichnis `views`. Der Name `product.htm` und der Speicherort dürfen nicht geändert werden, da das Template fest in der Software hinterlegt ist und nicht konfigurierbar oder anpassbar ist. Produktdaten können jedoch flexibel auch auf anderen Seiten eingebunden werden, zum Beispiel: * Startseite → Darstellung von Top-Sellern, Angeboten oder einer Produktauswahl. * Warenkorbseite → Cross-Selling-Produkte als Kaufempfehlungen. * Kategorieseiten & Suchergebnisse → Individuelle Produktlisten mit Filtern. * Checkout & Bestellbestätigung → Anzeige von ergänzenden Produkten oder Rabattaktionen. Mit `$wsProducts` lassen sich Produktinformationen dynamisch abrufen und individuell in verschiedenen Templates integrieren, um eine gezielte Präsentation von Artikeln zu ermöglichen. *** ## Variablen Für `$wsProducts` stehen keine Variablen zur Verfügung. *** ## Methoden ### \$wsProducts.load() Gibt ein Produkt anhand der Produkt-ID zurück. **Signatur**
    `$wsProducts.load(productId)` **Rückgabe**
    `map` - Product-Map mit allen Produktdaten. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | ---------------- | | `productId` | string | ja | ID des Produkts. | **Beispiel,** das ein Produkt lädt und den Namen des Produkts ausgibt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProduct = $wsProducts.load("100-12345") }} Name: {{= $myProduct.name }} ``` ### \$wsProducts.loadByNumber() Gibt ein Produkt anhand der Artikelnummer zurück. **Signatur**
    `$wsProducts.loadByNumber(itemNumber)` **Rückgabe**
    `map` - Product-Map mit allen Produktdaten. **Parameter** | **Parameter** | **Typ** | **Pflicht** | **Beschreibung** | | ------------- | ------- | ----------- | --------------------------- | | `itemNumber` | string | ja | Artikelnummer des Produkts. | **Beispiel,** das ein Produkt anhand der Artikelnummer lädt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProduct = $wsProducts.loadByNumber("ART-001") }} Name: {{= $myProduct.name }} ``` ### \$wsProducts.loadByCustomNumber() Gibt ein Produkt anhand einer benutzerdefinierten Nummer zurück, beispielsweise EAN oder GTIN. **Signatur**
    `$wsProducts.loadByCustomNumber(customNumber)` **Rückgabe**
    `map` - Product-Map mit allen Produktdaten. **Parameter** | **Parameter** | **Typ** | **Pflicht** | **Beschreibung** | | -------------- | ------- | ----------- | -------------------------- | | `customNumber` | string | ja | Benutzerdefinierte Nummer. | **Beispiel,** das ein Produkt anhand der GTIN lädt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProduct = $wsProducts.loadByCustomNumber("4006381333931") }} Name: {{= $myProduct.name }} ``` Mit Verwendung der Funktionen `$wsProducts.load..()` stehen verschiedene Variablen zur Verfügung, um Daten zum Produkt abzurufen und auszugeben. Nachfolgend eine Übersicht, welche Variablen verfügbar sind. #### Produkt-Daten (Rückgabe von \$wsProducts.load() ) Zunächst ist es notwendig, die Map mit den Produkt-Daten, wie im obigen Beispiel dargestellt, einer lokalen Variable zuzuweisen. Diese kann anschließend an verschiedenen Stellen im Template verwendet werden. **JSON-Ausgabe der Variablen** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "...", "active": "...", "name": "...", "descr": "...", "itemNumber": "...", "price": "...", "rawPrice": "...", "promotionInfo": "...", "taxRateId": "...", "storeId": "...", "custom": { ... }, "base": null, "variantSelection": { }, "getFullPriceInfo": "ƒ()" } ``` **Variablen in der Übersicht** | **Variable** | **Typ** | **Beschreibung** | | -------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `id` | string | Eindeutige vom Shop vergebene Produkt-ID. | | `active` | string | Gibt zurück, ob das Produkt im Shop aktiv ist.
    Rückgabewerte:
    - `always` - das Produkt ist immer aktiv.
    - `never` - das Produkt ist nie aktiv.
    - `test` - das Produkt ist im Testmodus aktiv. | | `name` | string | Name des Produkts. | | `descr` | string | Beschreibung des Produkts. | | `itemNumber` | string | Artikelnummer des Produkts. | | `price` | float | Aktuell gültiger Preis des Produkts. Ist ein Aktionspreis aktiv, steht hier der Aktionspreis. Siehe [Preis eines Produkts](#preis-eines-produkts). | | `rawPrice` | float | Standardpreis des Produkts, unabhängig von aktiven Aktionspreisen. Gedacht für die Anzeige als Streichpreis. | | `promotionInfo` | string | Text des aktiven Aktionspreises. Das Feld ist nur vorhanden, wenn ein Aktionspreis aktiv ist und dieser einen Text trägt. | | `taxRateId` | string | Steuersatz-ID des Produkts. | | `storeId` | string | Lagerartikelnummer des Produkts. | | `custom` | map | Enthält alle konfigurierten, freien Produktfelder des Produkts. | | `base` | map | Enthält die Daten des Basisprodukts, wenn es sich um eine Variante handelt. | | `variantSelection` | map | Enthält die gewählten Variantenattribute, beispielsweise Farbe und Größe. | | `getFullPriceInfo()` | ƒ() | Liefert Preis, Standardpreis und Aktionstext zu einem beliebigen Preisfeld. Siehe [Weitere Preisfelder auslesen](#weitere-preisfelder-auslesen). | ### \$wsProducts.variantInfo() Liefert die Varianten-Daten zu einem Produkt zurück. **Signatur**
    `$wsProducts.variantInfo(productId)` **Rückgabe**
    `map` - Map mit Varianten-Daten. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | -------------------------------------------------------- | | `productId` | string | ja | ID des Produkts, dessen Varianten geladen werden sollen. | **Beispiel,** das die Varianten-Infos eines Produkts lädt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myVariants = $wsProducts.variantInfo("100-12345") }} Anzahl Varianten: {{= $myVariants.numVariants }} ``` Mit Verwendung der Funktion `$wsProducts.variantInfo()` stehen verschiedene Variablen zur Verfügung, um Daten zum Produkt abzurufen und auszugeben. Nachfolgend eine Übersicht, welche Variablen verfügbar sind. #### Varianten-Daten (Rückgabe von \$wsProducts.variantInfo() ) Zunächst ist es notwendig, die Map mit den Varianten-Daten, wie im obigen Beispiel dargestellt, einer lokalen Variable zuzuweisen. Diese kann anschließend an verschiedenen Stellen im Template verwendet werden. **JSON-Ausgabe der Variablen** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "numVariants": 5, "variantAttributes": [ { "name": "Farbe", "options": [ { "name": "Rot" }, { "name": "Blau" } ] } ], "resolve": "ƒ()" } ``` **Variablen in der Übersicht** | **Variable** | **Typ** | **Beschreibung** | | ------------------- | ------- | ------------------------------------------- | | `numVariants` | int | Anzahl der Varianten. | | `variantAttributes` | array | Liste der Varianten-Attribute. | | `[$i].name` | string | Name des Attributs, beispielsweise "Farbe". | | `[$i].options` | array | Liste der Optionen. | | `[$i].name` | string | Name der Option, beispielsweise "Rot". | #### \$wsProducts.variantInfo().resolve() `resolve()` ist eine Methode des Rückgabewertes von `$wsProducts.variantInfo()`. Sie nimmt eine möglicherweise unvollständige oder ungültige Attributauswahl entgegen und gibt die nächstpassende existierende Variante zurück. **Warum** `resolve() `**benötigt wird**
    Variantenprodukte existieren nur in bestimmten Attributkombinationen.
    Wenn ein Kunde ein einzelnes Attribut ändert, beispielsweise die Farbe, ist die bisher gewählte Gesamtkombination möglicherweise nicht mehr verfügbar.
    `resolve()` findet in diesem Fall die nächstmögliche gültige Variante, ohne dass Sie alle verfügbaren Kombinationen selbst durchsuchen müssen.

    **Beispiel**
    Ein T-Shirt gibt es in diesen Kombinationen: | Farbe | Größe | | ----- | ----- | | Rot | S | | Blau | S | | Rot | L | Der Kunde sieht gerade "Rot, L" und klickt auf "Blau". Die Kombination "Blau, L" existiert jedoch nicht, weshalb `resolve()` stattdessen "Blau, S" liefert, also die einzig gültige Variante, bei der die Farbe Blau erhalten bleibt.
    Der Parameter `fixate` steuert dabei, welches Attribut als unveränderlich gilt. In diesem Fall ist es die Farbe, da der Nutzer die Farbe ausgewählt hat. **Signatur**
    `$variantInfo.resolve(selection, fixate)` **Parameter** | Name | Typ | Pflicht | Beschreibung | | ----------- | ------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `selection` | map | ja | Die aktuell gewählten Attributswerte.
    Die Map enthält Attributnamen als Schlüssel und gewählte Optionswerte als Werte, beispielsweise `{"Farbe": "Blau", "Größe": "L"}`.
    Nicht alle Attribute müssen gesetzt sein. | | `fixate` | string | ja | Name des Attributs, das der Nutzer soeben geändert hat.
    Dieser Wert wird von `resolve()` zwingend beibehalten.
    Alle anderen Attribute werden bei Bedarf angepasst, um eine gültige Kombination zu ergeben. |
    **Rückgabe**
    `map` - Ein Produktobjekt, das der aufgelösten Variante entspricht. Seine Struktur ist identisch mit der Rückgabe von [\$wsProducts.load()](/frontend/referenz/module/wsproducts#\$wsproducts-load). Im Fehlerfall, wenn also keine Variante mit dem fixierten Attributwert existiert, gibt `resolve()` `null` zurück.

    **Beispiel**
    Der Nutzer hatte "Rot, Größe L" gewählt und klickt auf "Blau". Weil "Blau, L" nicht existiert, liefert `resolve()` die nächstpassende Variante mit der Farbe Blau. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $varInfo = $wsProducts.variantInfo("100-12345") }} {{ var $resolved = $varInfo.resolve({"Farbe": "Blau", "Größe": "L"}, "Farbe") }} {{ if $resolved }} Variante auswählen {{ /if }} ``` *** ## Aktionen Für `$wsProducts` stehen keine Aktionen zur Verfügung. *** ## Beispiele In den folgenden Beispielen wird das Produkt einer Variable `$myProduct` zugewiesen. Das bedeutet, dass alle Produktinformationen über diese Variable abgerufen und weiterverarbeitet werden können. ### Name und Beschreibung des Produkts Name und Beschreibung sind Standard-Produktdatenfelder, die vom Shopsystem vorgegeben sind. Sie gehören zu den essenziellen Feldern, die zur Erfassung und Darstellung grundlegender Produktinformationen dienen und für die Bestellabwicklung unerlässlich sind. Die technischen Feldnamen sind fest definiert und werden in der folgenden Form angesprochen: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} $myProduct. ``` Die Syntax für den Zugriff auf den Produktnamen und die Produktbeschreibung lautet: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}

    {{= $myProduct.name }}

    {{= $myProduct.descr }}

    ``` ### Gewicht als Zusatz-Produktdatenfeld Im Gegensatz zu Standard-Produktdatenfeldern gehört das Gewicht zu den Zusatz-Produktdatenfeldern. Diese bieten erweiterte Möglichkeiten zur Erfassung und Darstellung von Produktmerkmalen, die über die grundlegenden Informationen hinausgehen. Zusatz-Produktdatenfelder sind: * Nicht zwingend für die Bestellabwicklung erforderlich, aber hilfreich für die Produktdarstellung. * Individuell anpassbar und können je nach Bedarf hinzugefügt werden. * Über das Admin Interface erstellt oder über die Produktdaten-Schnittstelle geliefert werden. Die technischen Namen dieser Felder werden in der Form angesprochen: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} $myProduct.custom. ``` Falls ein Feld `weight` im Admin-Bereich erstellt wurde, kann das Gewicht eines Produkts so ausgegeben werden: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}

    Gewicht: {{= $myProduct.custom.weight }} kg

    ``` ### Produktbilder Die Datenfelder für Produktbilder gehören nicht zu den Standardfeldern, sondern sind Zusatz-Produktdatenfelder. Um Produktbilder flexibel und in unterschiedlichen Größen auszugeben, müssen diese Felder als Datentyp MultiFormatImage angelegt werden. Dieser Feldtyp ermöglicht die Speicherung eines Bildes in mehreren Formaten und sorgt gleichzeitig für eine automatische Konvertierung, sodass die Bilder in den gewünschten Größen verfügbar sind. Die Anzahl der Zusatz-Produktdatenfelder mit diesem Typ ist nicht begrenzt, sodass beliebig viele Bilder für ein Produkt gespeichert werden können. Die Konfiguration der Bildgrößen erfolgt im Admin Interface im Service Bildkonverter. Dort können die gewünschten Formate festgelegt werden, die für verschiedene Anwendungsbereiche benötigt werden. Typischerweise werden vier Bildgrößen verwendet: * mini (Thumbnail) * klein * normal und * groß Die Formatnamen sind nicht fest vorgegeben. Sie vergeben sie frei im Service Bildkonverter. Im Template verwenden Sie genau den dort definierten Namen. Die Formatnamen in den folgenden Beispielen sind nur Beispiele. Im Admin Interface Service Bildkonverter wird auch das Speicherverzeichnis für die Bilder auf dem Server definiert. Der Pfad zum Bild wird dann durch die entsprechende Variable direkt mit ausgegeben. Der Zugriff auf Produktbilder erfolgt nach dem folgenden Schema * `$myProduct.custom..` Wurde beispielsweise das Feld `image01` für das Hauptbild des Produkts angelegt, können die Bilder in den verschiedenen Größen folgendermaßen ausgegeben werden: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $myProduct.name }} {{= $myProduct.name }} {{= $myProduct.name }} {{= $myProduct.name }} ``` ### Varianten eines Produktes Produkte, die in unterschiedlichen Ausführungen wie Größe, Farbe oder Material erhältlich sind, werden als Variantenprodukte angelegt. Varianten sind keine eigenständigen Artikel, sondern untergeordnete Versionen eines Hauptprodukts, die sich in bestimmten Merkmalen unterscheiden. Damit Varianten korrekt im Shop verwaltet und dargestellt werden können, werden spezielle Produktdatenfelder verwendet, die als typspezifische Produktdatenfelder bezeichnet werden. Diese Felder sind speziell darauf ausgerichtet, die Anforderungen von Variantenprodukten, Setprodukten und anderen komplexen Produktstrukturen zu unterstützen. Sie sind tief in der Shop-Software verankert, fest vorgegeben und können technisch nicht geändert werden. Das bedeutet, dass sowohl die Bezeichnung als auch die Spezifikationen dieser Felder nicht angepasst werden können. Das betrifft beispielsweise erlaubte Werte, Feldtypen und Vererbungsmechanismen. Die eigentlichen Produktinformationen einer Variante, wie Name, Beschreibung, Preis oder Bilder, werden über die Standard- und Zusatz-Produktdatenfelder gepflegt, die für die Varianten definiert wurden. Diese Daten können entweder individuell pro Variante festgelegt werden. Sind keine spezifischen Werte hinterlegt, werden sie automatisch vom Hauptprodukt geerbt. Für den Zugriff auf Varianten eines Produkts wird die folgende Syntax verwendet: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProductVariant = $wsProducts.variantInfo($myProduct.id) }} {{ foreach $myVariant in $myProductVariant.variantAttributes }}

    Variantename: {{= $myVariant.name }}

    {{ /foreach }} ``` ### Preis eines Produkts Jedes Produkt hat einen Verkaufspreis, der im Shop angezeigt wird. Zusätzlich kann ein Produkt zeitgesteuerte Aktionspreise tragen, die nur innerhalb eines gepflegten Zeitraums gelten. Dieser Abschnitt beschreibt zuerst die beiden Felder für den regulären Preis und den Aktionspreis, danach die Darstellung als Streichpreis, anschließend die Preise von Set-Produkten und zuletzt den Zugriff auf weitere Preisfelder. #### Aktueller Preis und Standardpreis Der Shop löst den Preis bei jedem Seitenaufruf neu auf. Sie müssen also nicht selbst prüfen, ob eine Aktion läuft. Dafür stehen drei Felder zur Verfügung. | **Variable** | **Typ** | **Beschreibung** | | --------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `price` | float | Der aktuell gültige Verkaufspreis. Ist ein Aktionspreis aktiv, steht hier der Aktionspreis, sonst der Standardpreis. | | `rawPrice` | float | Der Standardpreis, unabhängig von aktiven Aktionspreisen. | | `promotionInfo` | string | Der Text des aktiven Aktionspreises, beispielsweise "Sommeraktion". Das Feld ist nur vorhanden, wenn ein Aktionspreis aktiv ist und dieser einen Text trägt. | Damit die Preise mit der richtigen Währung ausgegeben werden, wird die Währungsformatierung automatisch aus den Shopeinstellungen im Admin Interface übernommen. Das bedeutet, dass die Währung entweder als ISO-Code (`EUR`) oder als Symbol (`€`) angezeigt wird, je nach Konfiguration des Shops. Ob die Preise im Shop netto (zzgl. MwSt.) oder brutto (inkl. MwSt.) behandelt werden, ist ebenfalls eine Einstellung, die im Admin Interface konfiguriert werden kann. #### Streichpreis und Aktionshinweis anzeigen Ein Streichpreis ist nur dann sinnvoll, wenn der Standardpreis tatsächlich über dem aktuellen Preis liegt. Prüfen Sie das deshalb vor der Ausgabe. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $myProduct.rawPrice > $myProduct.price }} {{= $myProduct.rawPrice | currency }} {{ /if }} {{= $myProduct.price | currency }} {{ if $myProduct.promotionInfo }} {{= $myProduct.promotionInfo }} {{ /if }} ``` Aktionspreise werden im Admin Interface je Preisfeld mit einem Von-Bis-Zeitraum gepflegt. Über die Schnittstelle geschieht das mit dem Feld `scheduledPrices`, beschrieben in der [API-Referenz Produkte](/schnittstellen/admin-interface-api/api-referenz-produkte#zeitgesteuerte-preise-aktionspreise). #### Preise von Set-Produkten Bei Set-Produkten wird der Preis aus dem Hauptprodukt und den Unterprodukten berechnet, und zwar bei jedem Seitenaufruf neu. Die Felder `price` und `rawPrice` enthalten dabei die Werte des Sets. Zusätzlich stehen folgende Felder zur Verfügung. | **Variable** | **Typ** | **Beschreibung** | | ------------------ | ------- | ------------------------------------------------------------------------------------------------------------------- | | `setPrice` | float | Preis des Sets, also der Wert, der auch in `price` steht. | | `setRawPrice` | float | Preis des Sets ohne Aktionspreise, also der Wert, der auch in `rawPrice` steht. | | `setOrgPrice` | float | Referenzpreis des Sets aus dem Preis des Hauptprodukts und den Preisen aller Unterprodukte. Dient als Streichpreis. | | `setDiscount` | float | Ersparnis in Prozent, also "Sie sparen X %". | | `setDiscountPrice` | float | Ersparnis als Betrag, also "Sie sparen X Euro". | Die Syntax für den Zugriff lautet: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $myProduct.isSetProduct }}

    Preis: {{= $myProduct.setPrice | currency }}

    Originalpreis: {{= $myProduct.setOrgPrice | currency }}

    Rabatt in Prozent: {{= $myProduct.setDiscount }} %

    Rabatt in Zahlen: {{= $myProduct.setDiscountPrice | currency }}

    {{ /if }} ``` Die fünf Set-Felder stehen nur bei Set-Produkten zur Verfügung. Bei allen anderen Produkten sind sie nicht vorhanden. Ob ein Produkt ein Set ist, sagt das Feld `isSetProduct`, das an jedem Produkt vorhanden ist. #### Preis im Warenkorb Der Preis einer Warenkorbposition wird beim Hinzufügen festgeschrieben. Betroffen sind `$wsBasket.items[].price` und die daraus abgeleiteten Werte `total`, `totalNet`, `totalGross` und `totalTax`. Endet eine Aktion, während der Artikel im Warenkorb liegt, behält die Position den Preis vom Zeitpunkt des Hinzufügens. Das gilt ebenso für die Unterprodukte eines Sets und für automatisch hinzugefügte Positionen. Das Produktobjekt innerhalb einer Warenkorbposition, also `$wsBasket.items[].product`, löst seinen Preis dagegen bei jedem Aufruf neu auf. Beide Werte können deshalb auseinanderlaufen. #### Änderungen an bestehenden Templates Die folgenden Änderungen können bestehende Templates betreffen. Prüfen Sie Ihre Preisausgaben, bevor Sie aktualisieren. | Feld | Änderung | | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `discountPrice` | Entfällt am Produkt- und am Varianten-Objekt. Der gleichnamige Schlüssel an einer Warenkorbposition, also `$wsBasket.items[].discountPrice`, bleibt unverändert. | | `totalPrice` | Entfällt am Produkt- und am Varianten-Objekt. | | `setPrice`, `setOrgPrice`, `setDiscount`, `setDiscountPrice` | Bisher an jedem Produkt vorhanden, an normalen Artikeln mit dem Wert 0.00. Jetzt nur noch an Set-Produkten vorhanden. Ausgaben ohne Prüfung auf `isSetProduct` bleiben an normalen Artikeln leer. | | `setOrgPrice` | Enthält jetzt zusätzlich den Preis des Hauptprodukts. Bisher summierte der Wert nur die Unterprodukte. Streichpreise auf Basis dieses Feldes werden dadurch höher. | | `setDiscount`, `setDiscountPrice` | Liefern jetzt auch dort Werte ungleich 0, wo vorher zwingend 0.00 stand. | | `price` | Enthält jetzt den aufgelösten Preis, bei Set-Produkten die Gesamtsumme des Sets. Das gilt für alle Felder vom Typ Preis, auch für Zusatzfelder unter `custom.`. | #### Weitere Preisfelder auslesen Neben dem Standardpreis kann ein Shop weitere Preisfelder als Zusatz-Produktdatenfelder führen. Auch diese Felder können Aktionspreise tragen, und auch der direkte Zugriff über `$myProduct.custom.` liefert bereits den aufgelösten Preis. `getFullPriceInfo()` brauchen Sie erst dann, wenn Sie zusätzlich den Standardpreis oder den Aktionstext eines solchen Feldes benötigen. **Signatur**
    `$myProduct.getFullPriceInfo(field)` **Rückgabe**
    `map` - Map mit den Feldern `price`, `rawPrice` und `promotionInfo`. Für ein unbekanntes Feld wird `null` zurückgegeben. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | -------- | ------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `field` | string | ja | Technischer Name des Preisfelds. Standard-Produktdatenfelder werden direkt angesprochen, beispielsweise `price`. Zusatz-Produktdatenfelder tragen das Präfix `custom.`, beispielsweise `custom.listPrice`. | **Beispiel,** das ein zusätzliches Preisfeld mit Streichpreis ausgibt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cPriceInfo = $myProduct.getFullPriceInfo("custom.listPrice") }} {{ if $cPriceInfo }} {{ if $cPriceInfo.rawPrice > $cPriceInfo.price }} {{= $cPriceInfo.rawPrice | currency }} {{ /if }} {{= $cPriceInfo.price | currency }} {{ /if }} ``` #### Wo diese Felder verfügbar sind Die Preisfelder gehören zum Produktobjekt selbst. Sie stehen deshalb überall zur Verfügung, wo ein Produktobjekt geliefert wird, und nicht nur bei `$wsProducts.load()`. Über Modul-Methoden: * `$wsProducts.load()`, `$wsProducts.loadByNumber()`, `$wsProducts.loadByCustomNumber()` und `$wsProducts.loadNext()` * `$wsProducts.variantInfo(id).resolve(selection, fixate)` * `$wsProduct.load()` und `$wsProduct.variantInfo(id).resolve(selection, fixate)` * `$wsCategories.loadProducts(categoryId)` * `$wsSearch.search(params, id).products` * `$wsWatchList.loadWatchList(watchListId).items[].product` * `$wsLastSeenProducts.load()` Über Seiten-Variablen und verschachtelte Objekte: * `$wsViews.current.info.product` und `$wsViews.current.info.products[]` * `$wsViews.current.info.basketItem.product` und `$wsViews.current.info.product` * `$wsBasket.items[].product` * `$wsNavigation.path[].object`, wenn `type` den Wert `product` hat * `$product.base`, also das Basisprodukt einer Variante ### Verfügbarkeit eines Produkts Neben allen anderen Produktinformationen ist die Verfügbarkeit eines Produkts eine der wichtigsten Informationen für den Käufer. Jedes Produkt kann mit einem Lagerbestand versehen werden, der darüber entscheidet, ob und in welcher Menge ein Artikel bestellt werden kann. Zusätzlich besteht die Möglichkeit, den aktuellen Lagerbestand und den zugehörigen Lieferstatus im Shop anzuzeigen. Der Zugriff auf den Lagerbestand erfolgt nicht direkt über `$wsProducts`, sondern über das separate Modul `$wsInventory` . ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myProductInventoryInfo = $wsInventory.load($myProduct.id) }} {{ if $myProductInventoryInfo.active }} Aktuelle Stückzahl: {{= $myProductInventoryInfo.amount }} {{ /if }} ``` Detaillierte Informationen für den Datenzugriff des Lagerbestands-Moduls finden Sie [hier](/frontend/referenz/module/wsinventory). Weitere Praxisbeispiele zur Umsetzung von Produkten und Produktvarianten finden Sie hier: → [Praxisbeispiele Produkte](/frontend/praxisbeispiele/produkte/anzeige-von-produkten) *** ## Weiterführende Links * [actions - Produkte](/konfiguration/actions-fehlertexte-e-mails/actions-produkte) * [API-Referenz Produkte](/schnittstellen/admin-interface-api/api-referenz-produkte) * [\$wsInventory - Lagerbestand & Verfügbarkeiten](/frontend/referenz/module/wsinventory) # $wsSecurity - Verschlüsselung Source: https://dokumentation.websale.de/frontend/referenz/module/wssecurity Modul $wsSecurity zum Verschlüsseln, Entschlüsseln und Hashen von Daten: sensible Informationen wie Passwörter und Token absichern. Mit dem `$wsSecurity` Modul können Sie Daten verschlüsseln, entschlüsseln und hashen. Es dient dem Schutz sensibler Daten wie Passwörter, Token oder persönliche Informationen. In diesem Abschnitt erfahren Sie, wie Sie die verschiedenen Verschlüsselungs- und Hash-Methoden einsetzen können. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsSecurity` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsSecurity | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "decrypt": "ƒ()", "encrypt": "ƒ()", "encryptManual": "ƒ()", "hash": "ƒ()" } ``` Anmerkung: `ƒ()` kennzeichnet eine Funktion. **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | ----------------- | ---------------- | ----------------------------------------------------------------------------------------------- | | `decrypt()` | string | Entschlüsselt Daten, die mit `encrypt()` verschlüsselt wurden. | | `encrypt()` | string | Verschlüsselt Daten mit einem in der Shop-Konfiguration hinterlegten Verschlüsselungsverfahren. | | `encryptManual()` | map | Verschlüsselt Daten wie `encrypt()`, gibt aber nur die einzelnen Bestandteil separat zurück. | | `hash()` | string | Berechnet einen kryptografischen Hash-Wert der Eingabedaten. | *** ## Templates Die Sicherheitsfunktionen können in jedem Template verwendet werden, typischerweise bei: * Formularen mit sensiblen Daten * Token-Generierung für Links * Passwort-Verarbeitung im Registrierungsprozess * Datenübergabe an externe Systeme *** ## Variablen Für `$wsSecurity` stehen keine Variablen zur Verfügung. *** ## Methoden ### \$wsSecurity.decrypt() Entschlüsselt Daten, die mit `$wsSecurity.encrypt()` verschlüsselt wurden. **Signatur**\ `$wsSecurity.decrypt(data)` **Rückgabe**\ `string` - Entschlüsselte Daten im Klartext. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | -------- | ------- | ----------- | --------------------------------------- | | `data` | string | ja | Verschlüsselte Daten im WEBSALE-Format. | **Beispiel,** das verschlüsselte Daten entschlüsselt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myDecryptedData = $wsSecurity.decrypt($encryptedData) }} ``` ### \$wsSecurity.encrypt() Verschlüsselt Daten mit einem in der Shop-Konfiguration hinterlegten Verschlüsselungsverfahren. Die verschlüsselten Daten können nur mit `decrypt()` wieder entschlüsselt werden. **Signatur**\ `$wsSecurity.encrypt(id, data, encryptionMethod, encoding)` **Rückgabe**\ `string` - Verschlüsselte Daten im WEBSALE-Format. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ------------------ | ------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | ja | ID des konfigurierten Verschlüsselungsverfahrens aus [security - Sicherheitsregeln](/konfiguration/security-sicherheitsregeln). | | `data` | string | ja | Zu verschlüsselnde Daten. | | `encryptionMethod` | string | ja | Verschlüsselungsmethode.
    Mögliche Werte:
    - `blowfish` - Blowfish Blockchiffre im ECB-Modus.
    - `aescbc` - AES Blockchiffre im CBC-Modus.
    - `aesgcm` - AES Blockchiffre im GCM-Modus.
    - `tdes` - Triple DES Blockchiffre im CBC-Modus. | | `encoding` | string | ja | Ausgabe-Encoding: `hex` oder `base64`. | **Beispiel,** das Daten mit AES-GCM verschlüsselt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myEncryptedData = $wsSecurity.encrypt("token_v1", "Sensible Daten", "aesgcm", "base64") }} ``` ### \$wsSecurity.encryptManual() Verschlüsselt Daten wie `encrypt()`, gibt aber die einzelnen Bestandteile (Ciphertext, Salt, Auth-Tag) separat zurück. Nützlich für die Integration mit externen Systemen, die ein anderes Format erwarten. **Signatur**\ `$wsSecurity.encryptManual(id, data, encryptionMethod, encoding)` **Rückgabe**\ `map` - Map mit den einzelnen Verschlüsselungsteilen. **Rückgabe-Felder** | **Rückgabewert** | **Typ** | **Beschreibung** | | ---------------- | ------- | -------------------------------------------------------- | | `ciphertext` | string | Verschlüsselte Daten. | | `keySalt` | string | Schlüssel zur Herleitung des Salts. | | `tag` | string | Auth-Token zur Authentizitätsprüfung (nur bei `aesgcm`). | **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ------------------ | ------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | ja | ID der Verschlüsselungskonfiguration aus `security.method.encrypt`. | | `data` | string | ja | Zu verschlüsselnde Daten. | | `encryptionMethod` | string | ja | Verschlüsselungsmethode.
    Mögliche Werte:
    - `blowfish` - Blowfish Blockchiffre im ECB-Modus.
    - `aescbc` - AES Blockchiffre im CBC-Modus.
    - `aesgcm` - AES Blockchiffre im GCM-Modus.
    - `tdes` - Triple DES Blockchiffre im CBC-Modus. | | `encoding` | string | ja | Ausgabe-Encoding: `hex` oder `base64`. | Beispiel, das Daten verschlüsselt und einzeln verwendet: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myResult = $wsSecurity.encryptManual("token_v1", "Sensible Daten", "aesgcm", "hex") }} Ciphertext: {{= $myResult.ciphertext }} Salt: {{= $myResult.keySalt }} Tag: {{= $myResult.tag }} ``` ### \$wsSecurity.hash() Berechnet einen kryptografischen Hash-Wert der Eingabedaten. Hash-Werte sind Einweg-Verschlüsselungen – sie können nicht zurück in die Originaldaten umgewandelt werden. Typischer Anwendungsfall: Passwort-Speicherung. **Signatur**\ `$wsSecurity.hash(id, data, hashingMethod, encoding)` **Rückgabe**\ `string` - Hash-Wert der Daten. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | --------------- | ------- | ----------- | ----------------------------------------------------- | | `id` | string | ja | ID der Hash-Konfiguration aus `security.method.hash`. | | `data` | string | ja | Zu hashende Daten. | | `hashingMethod` | string | ja | Hash-Methode: `sha256` oder `sha512`. | | `encoding` | string | ja | Ausgabe-Encoding: `hex` oder `base64`. | **Beispiel,** das ein Passwort mit einem konfigurierten Verfahren hasht. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myHashedPassword = $wsSecurity.hash("password_v1", $userPassword) }} ``` *** ## Aktionen Für `$wsSecurity` stehen keine Aktionen zur Verfügung. Die Verschlüsselung und das Hashing erfolgen direkt über die Methoden des Moduls. *** ## Beispiele In diesem Beispiel werden sensible Daten verschlüsselt und später wieder entschlüsselt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $encrypted = $wsSecurity.encrypt("token_v1", "Geheime Nachricht", "aesgcm", "base64") }} {{ var $decrypted = $wsSecurity.decrypt($encrypted) }} ``` ### Passwort hashen In diesem Beispiel wird ein Passwort gehasht. Der Hash-Wert kann später mit einem erneut gehashten Passwort verglichen werden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $hashedPassword = $wsSecurity.hash("password_v1", $password, "sha256", "hex") }} ``` *** ## Weiterführende Links * [security - Sicherheitsregeln](/konfiguration/security-sicherheitsregeln) # $wsSession - Session-Daten Source: https://dokumentation.websale.de/frontend/referenz/module/wssession Modul $wsSession: Session-Daten des Kunden auslesen, eigene Session-Variablen setzen und Bezahlstatus oder personalisierte Inhalte steuern. Mit dem `$wsSession` Modul können Sie Session-Daten des Kunden im Frontend auslesen und eigene Session-Variablen setzen. So können Sie personalisierte Inhalte anzeigen, Nutzerverhalten tracken oder den Session-Status bei Bezahlvorgängen prüfen. In diesem Abschnitt erfahren Sie, wie Sie Session-Daten lesen und schreiben können. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsSession` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsSession | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "...", "referer": "...", "userReferer": "...", "isInvalid": false, "isLocked": false, "get": "ƒ()", "set": "ƒ()" } ``` **Anmerkung:** `ƒ()` kennzeichnet eine Funktion. **Variablen und Methoden in der Übersicht** | **Name** | **Rückgabe-Typ** | **Beschreibung** | | ------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | Gibt die ID der aktuellen Session aus. | | `referer` | string | Gibt die externe Seite aus, über die der Nutzer in den Shop gelangt ist (z.B. Google, Facebook). | | `userReferer` | string | Gibt einen frei definierbaren Wert aus, den der Nutzer im Shop gesetzt hat. Gesetzt wird er über ein Eingabefeld mit dem Namen `ws_user_ref` im Template. | | `isInvalid` | bool | `true` wenn Session ungültig, sonst `false`. | | `isLocked` | bool | `true` wenn Session gesperrt (Bezahlvorgang), sonst `false`. | | `set()` | - | Setzt eine Session-Variable. | | `get()` | string | Gibt den Wert einer zuvor mit `set()` gespeicherten Session-Variable zurück. | *** ## Templates Auf die Daten des \$wsSession-Moduls kann auf allen Templates zugegriffen werden. *** ## Variablen ### \$wsSession.id Gibt die ID der aktuellen Session aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Session-ID: {{= $wsSession.id }} ``` ### \$wsSession.referer Gibt die externe Seite aus, über die der Nutzer in den Shop gelangt ist, zum Beispiel eine Suchmaschine oder ein soziales Netzwerk. Der Wert wird automatisch beim ersten Seitenaufruf gesetzt und ist auch in den Bestelldaten enthalten. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Referer: {{= $wsSession.referer }} ``` ### \$wsSession.userReferer Gibt einen frei definierbaren Wert aus, den der Nutzer im Shop gesetzt hat. Gesetzt wird er über ein Eingabefeld mit dem Namen `ws_user_ref` im Template. Ob und wie das Feld eingesetzt wird, entscheidet das jeweilige Template-Design. Der Wert ist ebenfalls in den Bestelldaten enthalten. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} User-Referer: {{= $wsSession.userReferer }} ``` ### \$wsSession.isInvalid Prüft, ob die Session gültig ist. Gibt `true` aus, wenn die Session ungültig ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsSession.isInvalid }} // Die Session ist ungültig. {{ else }} // Die Session ist gültig. {{ /if }} ``` ### \$wsSession.isLocked Gibt `true` aus, wenn die Session gesperrt ist. Eine Sperrung erfolgt während Online-Bezahlvorgängen (z.B. PayPal, Klarna), um parallele Änderungen am Warenkorb zu verhindern. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsSession.isLocked }} // Session ist wegen Bezahlvorgang gesperrt {{ else }} // Session ist nicht gesperrt {{ /if }} ``` *** ## Methoden ### \$wsSession.set() Setzt eine Session-Variable. Diese Werte bleiben über alle Folgeseiten hinweg gültig, bis sie überschrieben oder gelöscht werden. **Signatur**\ `$wsSession.set(key, value)` **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | -------- | ------- | ----------- | -------------------------- | | `key` | string | ja | Name der Session-Variable. | | `value` | string | ja | Wert der Session-Variable. | **Beispiel,** das eine Kategorie in der Session speichert. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ $wsSession.set("lastViewedCategory", "Laufschuhe") }} ``` ### \$wsSession.get() Gibt den Wert einer zuvor mit `set()` gespeicherten Session-Variable zurück. Gibt einen leeren String zurück, wenn die Variable nicht existiert. **Signatur**\ `$wsSession.get(key)` **Rückgabe**\ `string` - Wert der Session-Variable. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | -------- | ------- | ----------- | -------------------------- | | `key` | string | ja | Name der Session-Variable. | **Beispiel**, das eine gespeicherte Kategorie ausliest. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsSession.get("lastViewedCategory") }} Kategorie: {{= $wsSession.get("lastViewedCategory") }} {{ /if }} ``` *** ## Aktionen Aktionen zu diesem Modul sind separat im Kapitel Aktionen dokumentiert: [Session](/frontend/referenz/aktionen/session) *** ## Beispiele ### Ausgabe der aktuelle SessionID ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsSession.id}} ``` ### Prüfen, ob Session gesperrt ist Eine Session kann vorübergehend gesperrt werden, wenn ein Käufer eine Zahlungsart mit Online-Clearing wählt, bei der er auf eine externe Seite weitergeleitet wird (z. B. PayPal, Kreditkarte, Sofortüberweisung). Während der Sperrung sind keine weiteren Aktionen im Shop möglich, um Abweichungen zu verhindern – beispielsweise, wenn der Kunde in einem anderen Tab Produkte hinzufügt. Die Sperrung wird aufgehoben, sobald der Käufer den Bezahlvorgang abschließt oder abbricht. Sollte dies nicht möglich sein (z. B. wenn das externe System nicht erreichbar ist oder das Bezahlfenster geschlossen wurde), kann der Käufer eine neue Sitzung starten. Dabei bleibt sein Warenkorb und seine Anmeldung erhalten. Falls der Käufer den Shop während einer Sperrung aufruft, kann eine Hinweismeldung angezeigt werden: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsSession.isLocked }}

    Ihre Session ist aufgrund eines ausstehenden Zahlungsvorgangs gesperrt.

    {{ else }}

    Ihre Session ist nicht gesperrt.

    {{ /if }} ``` ### Session entsperren Falls eine Session aufgrund eines ausstehenden Bezahlvorgangs gesperrt ist, kann der Käufer sie manuell entsperren, indem er eine neue Sitzung startet. Dabei werden der aktuelle Warenkorb, alle bisherigen Eingaben sowie die Anmeldung übernommen. Dies ist hilfreich, wenn der Bezahlvorgang nicht abgeschlossen werden konnte, z. B. aufgrund eines geschlossenen Zahlungsfensters oder eines technischen Problems auf der externen Zahlungsseite. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsSession.isLocked }}    ...    {{ var $sessionUnlockAction = $wsActions.create("SessionUnlock") }}    
                                       
    {{ else }}    ... {{ /if }} ``` ### Bestimmte Sessiondaten setzen und abfragen Mit der Funktion `$wsSession.set` können individuelle Werte in der aktuellen Session eines Nutzers gespeichert werden. Diese Werte bleiben über alle Folgeseiten hinweg gültig, bis sie überschrieben oder gelöscht werden. Dies kann für verschiedene Zwecke genutzt werden, z. B. um: * Benutzervorlieben zu speichern (z. B. bevorzugte Sprache oder Kategorie). * Dynamische Shop-Anzeigen basierend auf vorherigem Verhalten zu steuern. * Kundenspezifische Anpassungen für ein personalisiertes Einkaufserlebnis vorzunehmen uvm. Angenommen, ein Kunde navigiert zu einer bestimmten Kategorie, z. B. "Laufschuhe". Wir können diese Information in der Session speichern, um sie auf anderen Seiten zu verwenden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ $wsSession.set("lastViewedCategory", "Laufschuhe") }} ``` Anschließend kann diese Information auf Folgeseiten genutzt werden, um dem Nutzer relevante Inhalte und Produktempfehlungen anzuzeigen: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsSession.get("lastViewedCategory") }}

    Entdecken Sie neue Produkte in der Kategorie {{= $wsSession.get("lastViewedCategory") }}.

    {{ /if }} ``` ### Zugriff auf Session-Daten am Beispiel des Referers Mit `$wsSession` können verschiedene in der Session gespeicherte Werte ausgelesen und genutzt werden. Ein Beispiel dafür ist der Referer, der angibt, von welcher externen Seite der Nutzer in den Shop gelangt ist. Dies kann nützlich sein, um zu analysieren, ob Besucher beispielsweise über eine Suchmaschine, eine Werbeanzeige oder einen Partnerlink gekommen sind. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}

    Referer: {{= $wsSession.referer }}

    ``` ### URL-Parameter auslesen und Session-Variable setzen Angenommen, es gibt einen URL-Parameter `promoCode`, der bestimmt, ob ein spezielles Werbebanner für eine Rabattaktion angezeigt werden soll. Wenn dieser Parameter vorhanden ist und einen bestimmten Wert hat, wird eine Session-Variable gesetzt, die dann auf anderen Seiten ausgelesen wird. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www.beispielshop.de/?promoCode=SUMMER2024 oder https://www.beispielshop.de/?promoCode=WELCOME10 ``` Beim Aufruf einer Seite wird geprüft, ob der Promo-Code als URL-Parameter übergeben wurde. Falls ja, wird der Wert in der Session gespeichert, um ihn später auswerten zu können. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsViews.current.params.promoCode }} {{ $wsSession.set("activePromo", $wsViews.current.params.promoCode) }} {{ /if }} ``` Nun kann auf einer anderen Seite geprüft werden, welcher Promo-Code gespeichert wurde, um entsprechend ein passendes Rabatt-Banner auszugeben: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsSession.get("activePromo") == "SUMMER2024" }}

    🔥 Sommer-Special! 10 % Rabatt mit dem Code SUMMER2024!

    {{ elseif $wsSession.get("activePromo") == "WELCOME10" }}

    🎉 Willkommen! 10 € Rabatt auf Ihre erste Bestellung mit WELCOME10!

    {{ else }}

    🛍️ Jetzt einkaufen und exklusive Angebote entdecken!

    {{ /if }} ``` *** ## Weiterführende Links * [Session](/frontend/referenz/aktionen/session) # $wsShipTrack - Sendungsverfolgung Source: https://dokumentation.websale.de/frontend/referenz/module/wsshiptrack Modul $wsShipTrack für Sendungsverfolgung und PLZ-Validierung: Tracking-Daten anzeigen und Lieferbarkeit von Adressen vor dem Checkout prüfen. Mit dem `$wsShipTrack` Modul können Sie auf Sendungsverfolgung und Lieferprüfungen zugreifen. Sie können dies z.B. für Tracking-Anzeigen oder PLZ-Validierungen bei der Lieferung verwenden. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsShipTrack` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsShipTrack | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "getTracking": "ƒ()", "zipCodeConfirmed": "ƒ()" } ``` Anmerkung: `ƒ()` kennzeichnet eine Funktion. **Methoden in der Übersicht** | **Methode** | **Rückgabe-Typ** | **Beschreibung** | | -------------------- | ---------------- | --------------------------------------------------------------------------------------- | | `getTracking()` | map | Gibt Tracking-Informationen eines Versanddienstleisters für bestimmte Sendungen zurück. | | `zipCodeConfirmed()` | bool | Gibt zurück, ob die Postleitzahl für eine bestimmte Bestellung bereits bestätigt wurde. | *** ## Templates Sendungsverfolgung und PLZ-Prüfungen werden typischerweise an folgenden Stellen eingesetzt: * Bestellbestätigung: Tracking-Link nach Versand der Bestellung. * Kundenkonto: Übersicht der Sendungsverfolgung für vergangene Bestellungen. * Checkout: PLZ-Validierung für Lieferoptionen. *** ## Aktionen Aktionen zu diesem Modul, die Änderungen auslösen, sind separat im Kapitel "Aktionen" dokumentiert (`ShipTrack`). *** ## Variablen Für `$wsShipTrack` stehen keine Variablen zur Verfügung. *** ## Methoden ### \$wsShipTrack.getTracking() Lädt Tracking-Informationen eines Versanddienstleisters für eine bestimmte Sendungsnummer. Die zurückgegebenen Daten hängen direkt vom jeweiligen Provider ab, schauen Sie sich daher bei der Integration die entsprechende Schnittstelle des Anbieters an (z.B. DHL-API). **Signatur**\ `$wsShipTrack.getTracking(id, trackingId)` **Rückgabe**\ `map` - eine Map mit dem Ergebnis der Tracking-Anfrage. Beispiel für die Struktur, die im Erfolgsfall zurückgegeben wird: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true, "lastErrorText": "", "lastErrorCode": 0, "data": } ``` Der Wert unter `data` wird direkt vom Provider (z.B. DHL) geliefert und ist daher abhängig von der jeweiligen Schnittstelle. Wenn keine Tracking-Informationen geladen werden konnten, ist `data` nicht vorhanden und `lastErrorText` sowie `lastErrorCode` enthalten die Fehlerdetails des Providers. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ------------ | ------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `id` | string | ja | ID des Versanddienstleisters (z.B. `DHL`). Wird unter [checkout.shipTrack](/frontend/funktionsubersicht/bestellablauf) konfiguriert. | | `trackingId` | string | ja | Sendungsnummer des Versanddienstleisters (z.B. die Sendungsnummer bei DHL). | **Beispiel,** das versucht, Tracking-Informationen zu laden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $tracking = $wsShipTrack.getTracking('DHL', '1234567890') }} {{ if $tracking.success }} // Tracking-Daten geladen. {{ else }} // keine Tracking-Daten gefunden. {{ /if }} ``` ### \$wsShipTrack.zipCodeConfirmed() Gibt zurück, ob die Postleitzahl für eine bestimmte Bestellung bereits bestätigt wurde. Diese Prüfung wird eingesetzt, um vor der Anzeige der Sendungsverfolgung sicherzustellen, dass es sich tatsächlich um den ursprünglichen Besteller handelt. **Signatur**\ `$wsShipTrack.zipCodeConfirmed(orderId)` **Rückgabe**\ `bool` - `true`, wenn die Postleitzahl für die angegebene Bestellung bereits bestätigt wurde, sonst `false`. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | --------- | ------- | ----------- | ------------------------------------------------------------------- | | `orderId` | string | ja | ID der Bestellung, für die die PLZ-Bestätigung geprüft werden soll. | **Beispiel,** das prüft, ob die Postleitzahl bestätigt wurde. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsShipTrack.zipCodeConfirmed($myOrderId) }} // Postleitzahl bestätigt. {{ else }} // Postleitzahl nicht bestätigt. {{ /if }} ``` *** ## Beispiele ### Sendungsverfolgung mit PLZ-Prüfung Dieses Beispiel prüft zunächst, ob die Postleitzahl bestätigt wurde und zeigt anschließend, sofern Tracking-Daten vorliegen, eine entsprechende Meldung an. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsShipTrack.zipCodeConfirmed($myOrderId) }}

    Lieferung an bestätigte Postleitzahl.

    {{ var $tracking = $wsShipTrack.getTracking('DHL', $myTrackingId) }} {{ if $tracking.success }}

    Tracking-Informationen verfügbar.

    {{ else }}

    Tracking konnte nicht geladen werden: {{= $tracking.lastErrorText }}

    {{ /if }} {{ else }}

    Bitte bestätigen Sie Ihre Postleitzahl, um die Sendungsverfolgung zu nutzen.

    {{ /if }} ``` *** ## Weiterführende Links * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [checkout - Bestellablauf](/konfiguration/checkout-bestellablauf) * [DHL-API (extern)](https://developer.dhl.com/api-reference/dhl-paket-de-sendungsverfolgung-post-paket-deutschland?language_content_entity=de\&lang=de#get-started-section) # $wsStore - Datenspeicherung Source: https://dokumentation.websale.de/frontend/referenz/module/wsstore Modul $wsStore als Key-Value-Speicher im Frontend: beliebige Daten unter frei wählbaren Schlüsseln ablegen, auslesen und gezielt löschen. Das `$wsStore`-Modul ist ein Key-Value-Store (Schlüssel-Wert-Speicher) für das Frontend. Darüber lassen sich beliebige Daten unter einem frei wählbaren Schlüssel ablegen, später wieder auslesen oder gezielt löschen. Es ist das passende Werkzeug überall dort, wo Informationen benötigt werden, die das Shopsystem im Standard nicht vorhält. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsStore` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsStore | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "set": "ƒ()", "get": "ƒ()", "delete": "ƒ()", "increment": "ƒ()" } ``` Anmerkung: `"ƒ()"` kennzeichnet eine Funktion. **Methoden in der Übersicht** | **Name** | **Rückgabe-Typ** | **Beschreibung** | | ------------- | ---------------- | ---------------------------------------------------------------------- | | `set()` | - | Speichert einen Wert unter dem angegebenen Schlüssel. | | `get()` | any / null | Gibt den gespeicherten Wert für den angegebenen
    Schlüssel zurück. | | `delete()` | - | Löscht den Eintrag für den angegebenen Schlüssel. | | `increment()` | - | Erhöht einen Zählerwert unter dem angegebenen Schlüssel. | *** ## Methoden ### \$wsStore.set() Speichert einen beliebigen Wert unter einem Schlüssel. Der Wert kann später über [get()](#\$wsstore-get "https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3987013651/wsStore#%24wsStore.get()") wieder abgerufen werden. Optional kann eine Gültigkeitsdauer (`ttl`) in Sekunden angegeben werden, nach der der Eintrag automatisch entfernt wird. Ohne `ttl` gilt ein Standardwert von 365 Tagen. **Signatur**\ `$wsStore.set(key, value, ttl)` ## **Rückgabe** **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | -------- | ------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | string | ja | Der Schlüssel, unter dem der Wert gespeichert wird.
    Frei wählbar.
    Empfehlung:
    sprechende, eindeutige Namen mit Präfix verwenden
    (z.B. `'productViews-' + $cProduct.id`), um Kollisionen
    mit anderen Modulen auszuschließen. | | `value` | any | ja | Der zu speichernde Wert. (Integer, String, Boolean, Objekt,
    Array) | | `ttl` | int | nein | Gültigkeitsdauer in Sekunden. Nach Ablauf wird der Eintrag
    automatisch entfernt. Ohne Angabe gilt ein Standardwert
    von 365 Tagen. | **Beispiel - Session-Marker setzen, damit ein Produktaufruf nur einmal pro Besucher gezählt wird** Um auf der Produktseite die Anzeige “X mal in den letzten 24 Stunden angesehen” zu realisieren, muss verhindert werden, dass derselbe Besucher den Zähler durch mehrfaches Neuladen der Seite verfälscht. Dafür wird pro Besucher ein Marker gesetzt - solange dieser Marker existiert, wird der Produktaufruf für diesen Besucher nicht erneut gezählt. [\$](/frontend/referenz/module/wssession#\$wssession-id "https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3046572054/wsSession#%24wsSession.id")wsSession.id ist die eindeutige Session-ID des aktuellen Besuchers. Sie wird automatisch vom Shopsystem bereitgestellt und muss nicht selbst vergeben werden. `14400` Sekunden entsprechen 4 Stunden – so lange gilt der Marker. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ $wsStore.set('productViewSession-' + $cProduct.id + $wsSession.id, true, 14400) }} ``` **Ergebnis**\ Ab dem Setzen liefert `$wsStore.get('productViewSession-')` für 4 Stunden den Wert `true` zurück. Der eigentliche Zähler, der dem Besucher die Anzeige *"X mal in den letzten 24 Stunden angesehen"* ausgibt, wird über [increment()](#\$wsstore-increment "https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3987013651/wsStore#%24wsStore.increment()") gepflegt. Erst nach Ablauf der 4 Stunden darf der Produktaufruf desselben Besuchers erneut in den Zähler einfließen. *** ### \$wsStore.get() Gibt den Wert zurück, der zuvor mit [set()](#\$wsstore-set "https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3987013651/wsStore#%5BhardBreak%5D%24wsStore.set()") unter dem angegebenen Schlüssel gespeichert wurde. Ist kein Eintrag vorhanden oder ist der Eintrag abgelaufen, wird `null` zurückgegeben. **Signatur**\ `$wsStore.get(key)` **Rückgabe**\ `any` - Der gespeicherte Wert, oder `null` , wenn kein Eintrag vorhanden ist oder der Eintrag abgelaufen ist. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | -------- | ------- | ----------- | ------------------------------------------------- | | `key` | string | ja | Der Schlüssel, dessen Wert abgerufen werden soll. | **Beispiel - Anzeige “X mal in den letzten 24 Stunden angesehen” auf der Produktseite** Um dem Besucher auf einer Produktdetailseite eine Anzeige wie “X mal in den letzten 24 Stunden angesehen” auszugeben, wird der zuvor mit [increment()](#\$wsstore-increment "https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3987013651/wsStore#%24wsStore.increment()") hochgezählte Wert ausgelesen. Existiert noch kein Eintrag (weil das Produkt in den letzten 24 Stunden noch nicht aufgerufen wurde), liefert [get()](#\$wsstore-get) null und die Anzeige wird übersprungen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $productViews = $wsStore.get('productViews-' + $cProduct.id) }} {{ if $productViews }} {{= $productViews }} mal in den letzten 24 Stunden angesehen {{ /if }} ``` **Ergebnis, wenn \$productViews den Wert 10 enthält** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 10 mal in den letzten 24 Stunden angesehen ``` *** ### \$wsStore.delete() Löscht den Eintrag für den angegebenen Schlüssel aus dem Store. Nach dem Löschen gibt [get()](#\$wsstore-get "https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3987013651/wsStore#%24wsStore.get()") für diesen Schlüssel `null` zurück. **Signatur**\ `$wsStore.delete(key)` ## **Rückgabe**\\ **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | -------- | ------- | ----------- | --------------------------------------------------- | | `key` | string | ja | Der Schlüssel, dessen Eintrag gelöscht werden soll. | *** ### \$wsStore.increment() Erhöht einen Zählerwert unter dem angegebenen Schlüssel um den angegebenen Wert. Existiert der Schlüssel noch nicht, wird er mit dem Wert von `amount` angelegt. Diese Methode sollte bevorzugt gegenüber einer Kombination aus [get()](#\$wsstore-get "https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3987013651/wsStore#%24wsStore.get()") und [set()](#\$wsstore-set "https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3987013651/wsStore#%5BhardBreak%5D%24wsStore.set()") verwendet werden, wenn ein Zähler erhöht werden soll.\ \ Das liegt daran, dass [get()](#\$wsstore-get "https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3987013651/wsStore#%24wsStore.get()") und [set()](#\$wsstore-set "https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3987013651/wsStore#%5BhardBreak%5D%24wsStore.set()") das Hochzählen in zwei Schritten durchführen - erst den aktuellen Wert lesen, dann den erhöhten Wert speichern. Rufen zwei Besucher die Seite gleichzeitig auf, lesen beide in Schritt 1 denselben Wert, beispielsweise 5. Beide speichern anschließend 6. Der Zähler steht am Ende auf 6, obwohl er auf 7 stehen müsste. Mit `increment()` passiert das Lesen und erhöhen in einem einzigen Schritt, sodass beide Aufrufe korrekt gezählt werden. **Signatur**\ `$wsStore.increment(key, amount, ttl)` **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | -------- | ------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | string | ja | Der Schlüssel, dessen Zählerwert erhöht werden soll. | | `amount` | int | nein | Der Wert, um den der Zähler erhöht wird.
    Standardmäßig `1`. | | `ttl` | int | nein | Gültigkeitsdauer in Sekunden. Nach Ablauf wird
    der Eintrag automatisch entfernt.
    Wird `ttl` weggelassen, gilt ein Standardwert
    von 365 Tagen. | **Beispiel - Produktaufrufe zählen, einmal pro Session** Ziel ist die Anzeige “X mal in den letzten 24 Stunden angesehen” auf der Produktseite. Damit derselbe Besucher den Zähler nicht durch mehrfaches Neuladen verfälscht, wird pro Session zusätzlich ein Marker gesetzt, der verhindert, dass derselbe Besucher das Produkt mehrfach zählt. [\$wsSession.id](/frontend/referenz/module/wssession) ist die eindeutige Session-ID des aktuellen Besuchers. Sie wird automatisch vom Shopsystem bereitgestellt und muss nicht selbst vergeben werden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myViewKey = 'productViews-' + $cProduct.id }} {{ var $mySessionKey = 'productViewSession-' + $cProduct.id + $wsSession.id }} {{ if not $wsStore.get($mySessionKey) }} {{ $wsStore.increment($myViewKey, 1, 86400) }} {{ $wsStore.set($mySessionKey, true, 14400) }} {{ /if }} ``` **Ergebnis**\ Der Zähler `productViews-` wird pro Besucher höchstens einmal alle 4 Stunden erhöht. Die anschließende Anzeige mit [get()](#\$wsstore-get "https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3987013651/wsStore#%24wsStore.get()") zeigt dem Besucher z.B.: “7 mal in den letzten 24 Stunden angesehen”. Nach Ablauf von 24 Stunden startet der Zähler automatisch wieder bei null. # $wsStores - Märkte & Filialen Source: https://dokumentation.websale.de/frontend/referenz/module/wsstores Modul $wsStores: konfigurierte Märkte und Filialen laden, ausgewählten Markt verwalten und Öffnungszeiten für Click & Collect anzeigen. Mit dem `$wsStores` Modul können Sie auf die konfigurierten Märkte und Filialen des Shops zugreifen. Typische Anwendungsfälle sind Click & Collect, Filialfinder und die Anzeige von Lagerbeständen im Markt. In diesem Abschnitt erfahren Sie, wie Sie Märkte laden, den ausgewählten Markt verwalten und Öffnungszeiten anzeigen können. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsStores` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsStores | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "selectedStore": null, "loadAllStores": "ƒ()", "loadStore": "ƒ()" } ``` Anmerkung: `ƒ()` kennzeichnet eine Funktion. **Variablen und Methoden in der Übersicht** | **Name** | **Rückgabe-Typ** | **Beschreibung** | | ----------------- | ---------------- | ------------------------------------------------------------------- | | `selectedStore` | map | Aktuell ausgewählter Markt oder `null`, wenn keiner ausgewählt ist. | | `loadAllStores()` | array | Lädt eine Liste aller verfügbaren Märkte. | | `loadStore()` | map | Lädt einen einzelnen Markt anhand seiner ID. | *** ## Templates Das \$wsStores Modul wird typischerweise verwendet auf: * Marktsuche-Seiten (Filialfinder) * Produktdetailseiten (Verfügbarkeit im Markt) * Checkout-Seiten (Click & Collect Auswahl) * Header/Footer (ausgewählter Markt anzeigen) *** ### Variablen ### \$wsStores.selectedStore Gibt den aktuell in der Session ausgewählten Markt aus. Ist `null`, wenn kein Markt ausgewählt wurde. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsStores.selectedStore }} Ihr Markt: {{= $wsStores.selectedStore.name }} {{ else }} Kein Markt ausgewählt {{ /if }} ``` *** ## Methoden ### \$wsStores.loadAllStores() Lädt eine Liste aller verfügbaren Märkte. **Signatur**\ `$wsStores.loadAllStores()` **Rückgabe**\ `array` - Liste mit Store-Maps. **Beispiel,** das alle Märkte lädt und anzeigt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $store in $wsStores.loadAllStores() }}

    {{= $store.name }} – {{= $store.city }}

    {{ /foreach }} ``` ## \$wsStores.loadStore() Lädt einen einzelnen Markt anhand seiner ID. **Signatur**\ `$wsStores.loadStore(storeId)` **Rückgabe**\ `map` - Store-Map mit allen Marktdaten. **Beispiel,** das einen Markt lädt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $store = $wsStores.loadStore(1) }} Marktname: {{= $store.name }} ``` Mit Verwendung der Rückgabe-Daten von `$wsStores.loadStore` stehen verschiedene Eigenschaften zur Verfügung, die verwendet werden können. Nachfolgend eine Übersicht, welche Eigenschaften verfügbar sind. Eigenschaften von `$wsStores.loadStore` | **Eigenschaften** | **Rückgabe-Typ** | **Beschreibung** | | ----------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------- | | `id` | int | Eindeutige ID des Marktes. | | `name` | string | Name des Marktes. | | `street` | string | Straße (ggf. mit Hausnummer). | | `zipCode` | string | Postleitzahl. | | `city` | string | Stadt. | | `country` | string | Land. | | `storageId` | string | ID des Markt-Lagers zur Abfrage des Lagerbestands über `$wsInventory.load()`. | | `clickAndCollect` | bool | Verfügbarkeit von Click & Collect. | | `openNow` | bool | Prüfung, ob der Markt aktuell geöffnet ist. | | `location` | map | GPS-Koordinaten (`latitude, longitude`) | | `latitude` | float | Breitengrad. | | `longitude` | float | Längengrad. | | `openingHours` | map | Öffnungszeiten nach Wochentag (0-6). | | `0-6` | array | Öffnungszeiten pro Wochentag (0=Sonntag, 1=Montag, … , 6=Samstag). | | `specialDays` | array | Tage mit abweichenden Öffnungszeiten (z.B. Feiertage). | | `month` | int | Monat (1-12). | | `day` | int | Tag (1-31). | | `times` | array | Öffnungszeiten für diesen Tag. | | `startTime` | map | Startzeit mit `hours` und `minutes`. | | `endTime` | map | Endzeit mit `hours` und `minutes`. | | `zipPrefix` | array | Postleitzahl-Präfixe, die diesem Markt zugeordnet sind (für automatische Marktvorschläge basierend auf Kundenadresse). | | `allowedSubshop` | array | Liste der Subshop-IDs, in denen dieser Markt verfügbar ist. | *** ## Aktionen Für `$wsStores` stehen keine Aktionen zur Verfügung. *** ## Beispiele ### Alle Märkte auflisten Beispiel, das alle Märkte mit Adresse und Öffnungsstatus anzeigt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $store in $wsStores.loadAllStores() }}

    {{= $store.name }}

    {{= $store.street }}, {{= $store.zipCode }} {{= $store.city }}

    {{ if $store.openNow }} Jetzt geöffnet {{ else }} Geschlossen {{ /if }}
    {{ /foreach }} ``` ### Filialauswahl als Dropdown darstellen Beispiel, das eine Filialauswahl als Dropdown zur Verfügung stellt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $action = $wsActions.create("SelectStore") }}
    ``` ### Click & Collect im Checkout Beispiel, das nur Märkte mit Click & Collect für Abholung anzeigt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $method in $wsConfig.shippingMethods }} {{ if $wsCheckout.selectedShippingMethod == $method.id and $method.type == "pickup" }} {{ var $storeAction = $wsActions.create("CheckoutStoreIdSelect") }}
    {{ if $storeAction.error }} {{ foreach $error in $storeAction.errors }}
    {{ if $error.code == "reservationFailed" }} Produkt nicht verfügbar in diesem Markt: {{= $error.details.productId }} {{ else }} {{= ifnull($error.text, $error.code) }} {{ /if }}
    {{ /foreach }} {{ /if }} {{ /if }} {{ /foreach }} ``` ### Lagerbestand im Markt prüfen Beispiel, das den Lagerbestand eines Produkts in einem bestimmten Markt prüft: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $store = $wsStores.selectedStore }} {{ if $store }} {{ var $inventory = $wsInventory.load($product.id, $store.storageId) }} {{ if $inventory.active }}

    Verfügbar in {{= $store.name }}: {{= $inventory.amount }} Stück

    {{ else }}

    Nicht verfügbar in {{= $store.name }}

    {{ /if }} {{ /if }} ``` *** ## Weiterführende Links * [\$wsInventory](/frontend/referenz/module/wsinventory) * [API-Referenz Stores](/schnittstellen/admin-interface-api/api-referenz-stores) # $wsStripe - Stripe Source: https://dokumentation.websale.de/frontend/referenz/module/wsstripe Modul $wsStripe: Konfigurationsdaten für Stripe.js bereitstellen, Stripe im Frontend initialisieren und den aktuellen Zahlungsstatus auswerten. Mit dem `$wsStripe` Modul können Sie Zahlungsinformationen zu Stripe abrufen. Es stellt die Konfigurationsdaten für die Stripe.js-Integration sowie Statusinformationen zum aktuellen Zahlungsvorgang bereit. In diesem Abschnitt erfahren Sie, wie Sie Stripe im Frontend initialisieren und den Zahlungsstatus auswerten können. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsStripe` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsStripe | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "configuration": { "publishableKey": "...", "targetAccount": "..." }, "createCustomerSession": "ƒ()", "paymentCanceled": false, "paymentFailed": false, "paymentPending": false } ``` Anmerkung: `"ƒ()"` kennzeichnet eine Funktion. **Variablen und Methoden in der Übersicht** | **Name** | **Typ** | **Beschreibung** | | ------------------------- | ------- | -------------------------------------------------------------------------- | | `configuration` | map | Map mit Stripe-Konfigurationsdaten. | | `publishableKey` | string | Öffentlicher Stripe-Schlüssel für die Integration im Frontend. | | `targetAccount` | string | Stripe Connected Account ID (für Plattform-Zahlungen). | | `paymentCanceled` | bool | `true` wenn die Zahlung abgebrochen wurde. | | `paymentFailed` | bool | `true` wenn die Zahlung fehlgeschlagen ist. | | `paymentPending` | bool | `true` wenn die Zahlung noch aussteht. | | `createCustomerSession()` | map | Erstellt eine Stripe Customer Session für den aktuell eingeloggten Kunden. | *** ## Templates Das `$wsStripe` Modul wird typischerweise im Checkout-Bereich verwendet,\ insbesondere auf der Zahlungsseite. Die Konfigurationsdaten werden zur\ Initialisierung des Stripe.js-Objekts im Frontend benötigt. *** ## Variablen ### \$wsStripe.configuration Gibt die Stripe-Konfigurationsdaten aus. Wird zur Initialisierung des Stripe-Objekts im Frontend verwendet. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myStripeConfig = $wsStripe.configuration }} ``` #### \$wsStripe.configuration.publishalbeKey Gibt den öffentlichen Stripe-Schlüssel aus. Dieser Schlüssel wird zur Initialisierung von Stripe.js im Browser benötigt und ist sicher für die Verwendung im Frontend. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Publishable Key: {{= $wsStripe.configuration.publishableKey }} ``` #### \$wsStripe.configuration.targetAccount Gibt die Stripe Connected Account ID aus. Wird nur bei Plattform- oder Marktplatz-Zahlungen benötigt, wenn Zahlungen an einen verbundenen Account weitergeleitet werden. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Target Account: {{= $wsStripe.configuration.targetAccount }} ``` ### \$wsStripe.paymentCanceled Gibt `true` aus, wenn die Zahlung abgebrochen wurde. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsStripe.paymentCanceled }} // Die Zahlung wurde abgebrochen {{ /if }} ``` ### \$wsStripe.paymentFailed Gibt `true` aus, wenn die Zahlung fehlgeschlagen ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsStripe.paymentFailed }} // Die Zahlung ist fehlgeschlagen {{ /if }} ``` ### \$wsStripe.paymentPending Gibt `true` aus, wenn die Zahlung noch aussteht. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsStripe.paymentPending }} // Die Zahlung wird verarbeitet {{ /if }} ``` *** ## Methoden ### \$wsStripe.createCustomerSession() Erstellt eine Stripe Customer Session für den aktuell eingeloggten Kunden. Die Session ermöglicht sicheren Zugriff auf gespeicherte Zahlungsmethoden und Kundendaten direkt im Frontend. **Signatur**\ `$wsStripe.createCustomerSession()` **Rückgabe**\ `map` - Customer Session Objekt mit folgenden Attributen: | **Attribut** | **Typ** | **Beschreibung** | | -------------- | --------- | ----------------------------------------------------------- | | client\_secret | string | Geheimer Schlüssel für den sicheren Zugriff auf den Kunden. | | components | object | Konfiguration für aktivierte Stripe-Komponente. | | customer | string | ID des Kunden, für den die Session erstellt wurde. | | expires\_at | timestamp | Zeitpunkt, zu dem die Session abläuft. | **Beispiel,** das eine Customer Session erstellt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myCustomerSession = $wsStripe.createCustomerSession() }} const customerSessionClientSecret = "{{= $myCustomerSession.client_secret }} ``` *** ## Aktionen Für `$wsStripe` stehen keine Aktionen zur Verfügung. *** ## Beispiele ### Zahlungsstatus prüfen ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsStripe.paymentCanceled }}
    Die Zahlung wurde abgebrochen.
    {{ /if }} {{ if $wsStripe.paymentFailed }}
    Die Zahlung ist fehlgeschlagen.
    {{ /if }} {{ if $wsStripe.paymentPending }}
    Die Zahlung wird verarbeitet.
    {{ /if }} ``` *** ## Weiterführende Links * [payment - Zahlungsmethoden](/konfiguration/payment-zahlungsmethoden) * [\$wsCheckout](/frontend/referenz/module/wscheckout) * [https://docs.stripe.com/api](https://docs.stripe.com/api) # $wsSubshop - Subshop Source: https://dokumentation.websale.de/frontend/referenz/module/wssubshop Mit dem `$wsSubshop` Modul können Sie auf Subshop-Daten zugreifen. Typische Anwendungsfälle sind Sprachumschalter oder Links zwischen verschiedenen Länder- und Sprachversionen des Shops. In diesem Abschnitt erfahren Sie, wie Sie Subshop-Informationen auslesen und zwischen Subshops verlinken können. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsSubshop` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsSubshop | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "currentTime": "2026-06-26T09:18:59.000Z", "id": "deutsch", "language": { "isoCode": "DE", "name": "Deutsch" }, "subshopUrl": "ƒ()", "subshops": ["deutsch"], "timeZone": "Europe/Berlin" } ``` Anmerkung: `ƒ()` kennzeichnet eine Funktion. **Variablen und Methoden in der Übersicht** | **Name** | **Typ** | **Beschreibung** | | -------------- | ------- | -------------------------------------------------------------------------------------------------------- | | `id` | string | ID des aktuellen Subshops. | | `currentTime` | string | Aktueller Zeitstempel im ISO-8601-Format. | | `timeZone` | string | Im Shop konfigurierte Zeitzone (z. B. `"Europe/Berlin"`). | | `language` | map | Map mit Sprachinformationen des Subshops. | | `isoCode` | string | ISO-Sprachcode (z.B. `“DE”`, `“EN”`). | | `name` | string | Name der Sprache (z.B. `“Deutsch”`, `“Englisch”`). | | `subshops` | array | Liste aller verfügbaren Subshop-IDs. | | `subshopUrl()` | string | Gibt die URL zur Startseite des angegebenen Subshops zurück, optional mit zusätzlichen Query-Parametern. | *** ## Templates Subshop-Daten werden typischerweise an folgenden Stellen eingesetzt: * Header: Sprachumschalter zwischen verschiedenen Subshops. * Footer: Links zu anderen Länder-/Sprachversionen des Shops. * Inhalte: Länderspezifische Hinweise oder Anpassungen. *** ## Variablen ### \$wsSubshop.id Gibt die ID des aktuellen Subshops aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Aktueller Subshop: {{= $wsSubshop.id }} ``` ### \$wsSubshop.currentTime Gibt den aktuellen Zeitstempel im ISO-8601-Format aus (z. B. `2026-06-26T09:18:59.000Z`). Diesen Wert formatieren Sie mit der globalen Funktion [`dateFmt()`](/frontend/referenz/funktionen#datefmt) in ein lesbares Datum oder eine Uhrzeit. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsSubshop.currentTime | dateFmt("%Y") }} ``` Damit geben Sie z. B. die aktuelle Jahreszahl aus, etwa für eine Copyright-Angabe im Footer. ### \$wsSubshop.timeZone Gibt die im Shop konfigurierte Zeitzone aus (z. B. `Europe/Berlin`). Dies ist die Zeitzone, die [`dateFmt()`](/frontend/referenz/funktionen#datefmt) verwendet, wenn beim Formatieren keine eigene Zeitzone angegeben wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Zeitzone des Shops: {{= $wsSubshop.timeZone }} ``` ### \$wsSubshop.language Gibt eine Map mit Sprachinformationen des aktuellen Subshops aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Sprache: {{= $wsSubshop.language.name }} ({{= $wsSubshop.language.isoCode }}) ``` #### \$wsSubshop.language.isoCode Gibt den ISO-Sprachcode des aktuellen Subshops aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ISO-Code: {{= $wsSubshop.language.isoCode }} ``` #### \$wsSubshop.language.name Gibt den Namen der Sprache des aktuellen Subshops aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Aktuelle Sprache: {{= $wsSubshop.language.name }} ``` ### \$wsSubshop.subshops Gibt eine Liste aller verfügbaren Subshop-IDs aus. Nützlich für die Erstellung eines Sprachumschalters oder einer Länderauswahl. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $myShopId in $wsSubshop.subshops }} {{= $myShopId }} {{ /foreach }} ``` *** ## Methoden ### \$wsSubshop.subshopUrl() Gibt die URL zur Startseite des angegebenen Subshops zurück. Die URL berücksichtigt automatisch die Domain des Ziel-Subshops sowie das Protokoll des aktuellen Aufrufs (`http` beziehungsweise `https`). **Signatur**
    `$wsSubshop.subshopUrl(subshopId, params)` **Rückgabe**
    `string` - URL des angegebenen Subshops. `null`, wenn die Subshop-ID leer ist oder kein Subshop mit dieser ID existiert. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | ------------------------------------------------------------------------------------------------------------ | | `subshopId` | string | ja | ID des Ziel-Subshops. | | `params` | map | nein | Map mit zusätzlichen Query-Parametern, die an die URL angehängt werden. Die Werte müssen Zeichenketten sein. | **Beispiel,** das die URL eines Subshops ausgibt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} URL: {{= $wsSubshop.subshopUrl('english') }} ``` **Beispiel** mit zusätzlichen Query-Parametern. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} URL: {{= $wsSubshop.subshopUrl('english', { campaign: 'spring-sale' }) }} ``` Ein typischer Anwendungsfall für `params` ist die Übernahme des Warenkorbs beim Subshop-Wechsel, siehe [Warenkorb beim Subshop-Wechsel mitnehmen](#warenkorb-beim-subshop-wechsel-mitnehmen). *** ## Aktionen Für `$wsSubshop` stehen keine Aktionen zur Verfügung. *** ## Beispiele ### HTML-Lang-Attribut setzen ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` ### Aktuelle Sprache anzeigen ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}

    Sie befinden sich im Shop: {{= $wsSubshop.language.name }}

    ``` ### Aktuelle Jahreszahl im Footer ausgeben Kombiniert `currentTime` mit `dateFmt`, um z. B. eine Copyright-Zeile immer aktuell zu halten. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}

    © {{= $wsSubshop.currentTime | dateFmt("%Y") }} Mein Onlineshop

    ``` **Ergebnis** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} © 2026 Mein Onlineshop ``` *** ## Warenkorb beim Subshop-Wechsel mitnehmen Jeder Subshop verfügt über eine eigene Session und somit auch über einen eigenen Warenkorb. Diese Warenkörbe bleiben dauerhaft getrennt. Sie werden nicht miteinander abgeglichen und eine Bestellung gehört immer zu genau dem Subshop, in dem der Bestellvorgang durchlaufen wurde. Wechselt ein Kunde den Subshop, startet er dort deshalb zunächst mit einem leeren Warenkorb. Beim Wechsel lassen sich die Positionen aber einmalig übernehmen. Dazu hängen Sie den Query-Parameter `transfer` mit der ID der aktuellen Session an die Ziel-URL an. Der Ziel-Subshop liest daraufhin den Warenkorb der angegebenen Session aus und legt die Positionen in seinem eigenen Warenkorb neu an. Dadurch entsteht kein gemeinsamer Warenkorb aus beiden Warenkörben, sondern eine Kopie des Warenkorbs zum Zeitpunkt des Wechsels. Anschließend entwickeln sich beide Warenkörbe unabhängig voneinander weiter. Spätere Änderungen im Quell-Subshop erreichen den Ziel-Subshop nicht mehr. Es gibt dafür keinen Konfigurationsknoten, die Funktion hängt allein an diesem Parameter. ### Verwendung im Template ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $subshopId in $wsSubshop.subshops }} {{ if $subshopId != $wsSubshop.id }} {{= $subshopId }} {{ /if }} {{ /foreach }} ``` Der Parameter wird auf jeder Seite des Ziel-Subshops ausgewertet, nicht nur auf der Startseite. Sie können den Transfer daher auch mit einem Deeplink kombinieren. ### Was übernommen wird Der Transfer ist ein Kopiervorgang. Der Warenkorb der Quell-Session bleibt unverändert bestehen. Übernommen werden ausschließlich die Warenkorbpositionen. Login, Adressen, Gutscheine und der Stand des Bestellablaufs werden hingegen nicht übertragen. Die Positionen werden im Ziel-Subshop nicht einfach kopiert, sondern neu aufgebaut: 1. Das Produkt wird zunächst über die Produkt-ID gesucht. Wird es darüber nicht gefunden, sucht der Shop ersatzweise über die Artikelnumme**r**. Diese Suche berücksichtigt nur Produkte, die im Ziel-Subshop aktiv sind. 2. Ist eine Variante angegeben, wird geprüft, ob sie am Zielprodukt existiert. 3. Set-Produkte werden vollständig neu gebildet, also Hauptposition und Unterpositionen, geprüft gegen die Set-Definition im Ziel-Subshop. 4. Die Menge wird gegen die im Ziel-Subshop zulässige Höchstmenge geprüft. 5. Preise und Steuern werden im Ziel-Subshop neu ermittelt. Ein Preis- oder Währungsunterschied zwischen den Subshops schlägt also unmittelbar durch. 6. Der Bestand wird im Ziel-Subshop neu reserviert. Positionen, die sich im Ziel-Subshop nicht auflösen lassen, werden übersprungen. Die übrigen Positionen werden trotzdem übernommen. Der Warenkorb im Ziel-Subshop kann nach dem Transfer also weniger Positionen enthalten als ursprünglich. Jeder übersprungene Fall wird protokolliert, siehe [Protokollierung](#protokollierung). Nicht übernommen werden außerdem: * Automatische Beigaben aus [`basket.autobasket`](/konfiguration/basket-warenkorb#basketautobasket---beigaben-zum-warenkorb). Diese werden im Ziel-Subshop anhand der dort gültigen Konfiguration neu erzeugt. * Bereits vorhandene identische Positionen. Liegt im Ziel-Warenkorb bereits dieselbe Position mit derselben Menge, wird sie nicht ein zweites Mal angelegt. Weicht die Menge ab, wird die Position zusätzlich angelegt. ### Voraussetzungen * Das Produkt muss im Ziel-Subshop vorhanden und bestellbar sein. * Bei Set-Produkten muss die Set-Definition im Ziel-Subshop zur übertragenen Zusammenstellung passen. * Für die Position muss im Ziel-Subshop ausreichend Bestand reservierbar sein. Der Wert von `transfer` ist eine Session-ID. Wer diese kennt, kann den zugehörigen Warenkorb auslesen. Verwenden Sie den Parameter deshalb ausschließlich für Links innerhalb des eigenen Shops und geben Sie die Session-ID nicht an Dritte weiter, etwa über externe Tracking-Parameter oder Weiterleitungen auf fremde Domains. ### Protokollierung Übersprungene Positionen erscheinen im Logmanager mit den folgenden Codes: | **Code** | **Bedeutung** | | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `basket.subshopBasketModuleNotExists` | Die angegebene Session enthält keinen Warenkorb. | | `basket.subshopBasketEmpty` | Der Warenkorb der angegebenen Session ist leer. | | `basket.subshopBasketProductInvalid` | Die Position enthält weder Produkt-ID noch Artikelnummer, oder es handelt sich um eine automatische Beigabe. | | `basket.subshopBasketProductNotFoundByNumber` | Das Produkt wurde über die Produkt-ID nicht gefunden, und auch die Suche über die Artikelnummer blieb ohne Treffer. | | `basket.subshopBasketProductNotFound` | Über die Artikelnummer wurde zwar eine Produkt-ID ermittelt, das Produkt ließ sich damit aber nicht laden. | | `basket.subshopBasketProductNoVariant` | Die Variante existiert an dem über die Produkt-ID gefundenen Produkt nicht. | | `basket.subshopBasketProductNoVariantNumber` | Die Variante existiert an dem über die Artikelnummer gefundenen Produkt nicht. | | `basket.subshopBasketNoVariantFound` | Das Zielprodukt hat Varianten, in der Position ist aber keine angegeben. | | `basket.subshopBasketSetMismatch` | Das Zielprodukt ist ein Set, die Quellposition aber keine Set-Hauptposition. | | `basket.subshopBasketSetChildInvalid` | Eine Unterposition des Sets lässt sich im Ziel-Subshop nicht auflösen. | | `basket.subshopBasketSetDefinitionMismatch` | Die Zusammenstellung passt nicht zur Set-Definition im Ziel-Subshop. | | `basket.isValidBasketItemQuantityInvalid` | Die Menge überschreitet die zulässige Höchstmenge, also `maxItemQuantity` aus [`basket.basket`](/konfiguration/basket-warenkorb#basketbasket---einstellungen-für-den-warenkorb) oder eine am Produkt hinterlegte niedrigere Maximalmenge. | | `basket.subshopBasketSetNotReserved` | Der Bestand für ein Set-Produkt konnte im Ziel-Subshop nicht reserviert werden. | | `basket.isValidBasketItemInventoryNotReserved` | Der Bestand konnte im Ziel-Subshop nicht reserviert werden. | Scheitert die Suche über die Artikelnummer aus technischen Gründen, erscheinen zusätzlich die Codes `basket.searchProductIdByNumberNoDescriptor`, `basket.searchProductIdByNumberNoActiveProperty` oder `basket.searchProductIdByNumberSearchFailed`. Ist die in `transfer` angegebene Session unbekannt oder nicht mehr lesbar, geschieht nichts und es wird auch nichts protokolliert. Prüfen Sie in diesem Fall zuerst, ob die übergebene Session-ID noch gültig ist. ### Abgrenzung zu Cookie- und Konto-Warenkorb Der Cookie-Warenkorb (`cookieBasketActive`) und der Konto-Warenkorb (`accountBasketActive`) aus [`basket.basket`](/konfiguration/basket-warenkorb#basketbasket---einstellungen-für-den-warenkorb) sind kein Ersatz für den Transfer. Sie sichern den Warenkorb über Sitzungen beziehungsweise Geräte hinweg, nicht über Subshops. Da Subshops in der Regel unter eigenen Domains laufen, steht das Warenkorb-Cookie im anderen Subshop nicht zur Verfügung. *** # Weiterführende Links * [general - Allgemeine Shopeinstellungen](/konfiguration/general-allgemeine-shopeinstellungen) * [basket - Warenkorb](/konfiguration/basket-warenkorb) - Konfiguration des Warenkorbs, Beigaben und Höchstmengen. * [\$wsSession](/frontend/referenz/module/wssession) - Session-ID, die der Warenkorb-Transfer verwendet. * [Funktionen](/frontend/referenz/funktionen) - globale Funktionen wie `dateFmt`, `isoToUnix` und `unixToIso` zum Verarbeiten von Zeitstempeln. # $wsTestMode - Testmodus Source: https://dokumentation.websale.de/frontend/referenz/module/wstestmode Modul $wsTestMode: prüfen, ob der Testmodus aktiv ist, und neue Funktionen, Designs oder Produkte für reguläre Besucher unsichtbar testen. Mit dem `$wsTestMode` Modul können Sie prüfen, ob der Testmodus aktiv ist, und Inhalte entsprechend steuern. Im Testmodus können Sie neue Funktionen, Designs oder Produkte testen, ohne dass diese für reguläre Besucher sichtbar sind. Zusätzlich zeigt das Modul an, ob das Debugging aktiviert ist und ob Zahlungen im Testmodus als fehlgeschlagen simuliert werden sollen. In diesem Abschnitt erfahren Sie, wie Sie den Testmodus abfragen und testspezifische Inhalte anzeigen können. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsTestMode` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsTestMode | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": false, "debug": false, "makePaymentFail": false } ``` **Variablen in der Übersicht** | **Variable** | **Typ** | **Beschreibung** | | ----------------- | ------- | --------------------------------------------------------------------- | | `active` | bool | Prüft, ob der Testmodus aktiviert ist. | | `debug` | bool | Prüft, ob Debugging im Testmodus aktiviert ist. | | `makePaymentFail` | bool | Prüft, ob Zahlungen im Testmodus als fehlgeschlagen simuliert werden. | *** ## Templates Mit der Template-Engine können bestimmte Inhalte gezielt für den Testmodus sichtbar gemacht werden. Das ermöglicht es, spezielle Funktionen oder Designs zu testen, ohne dass sie für reguläre Besucher des Shops sichtbar sind. Für die Passwort-Eingabe zur Aktivierung des Testmodus wird ein spezielles View-Template benötigt. Standardmäßig lautet der Name `testMode.htm`, das sich im Verzeichnis `views` befindet. Das Template kann umbenannt werden. Der neue Template-Name muss dann jedoch in den Konfigurationseinstellungen im [Admin Interface](/admin-interface) hinterlegt werden. Die Konfigurationsoption befindet sich an der Stelle, an der auch das Passwort für den Testmodus hinterlegt und geändert werden kann. *** ## Variablen ### \$wsTestMode.active Gibt aus, ob der Testmodus aktiviert ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsTestMode.active }} // Test-Modus ist aktiv {{ /if }} ``` ### \$wsTestMode.debug Gibt `true` aus, wenn das erweiterte Debugging aktiviert ist. Im Debug-Modus werden zusätzliche Informationen wie Variablenwerte oder Ladezeiten angezeigt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsTestMode.debug }} // Debugging ist aktiv {{ /if }} ``` ### \$wsTestMode.makePaymentFail Gibt `true` aus, wenn Zahlungen im Testmodus als fehlgeschlagen simuliert werden. Die Simulation wird beim Aktivieren des Testmodus über den Parameter `makePaymentFail` der Aktion [TestModeOn](/frontend/referenz/aktionen/testmode#testmodeon) eingeschaltet. Dadurch laufen Bestellungen gezielt in den Fehlerfall, sodass die dafür vorgesehenen Templates und Abläufe geprüft werden können. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsTestMode.makePaymentFail }} // Zahlungen werden als fehlgeschlagen simuliert {{ /if }} ``` *** ## Methoden Für `$wsTestMode` stehen keine Methoden zur Verfügung. *** ## Aktionen Für `$wsTestMode` stehen keine Aktionen zur Verfügung. *** ## Beispiele zur Verwendung des Testmodus ### Link zum Aktivieren des globalen Testmodus Der Link kann versendet werden, wenn man den Shopbetreiber darüber informiert hat, dass Änderungen im Testmodus integriert worden sind und er sich diese über den folgenden Link ansehen kann: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www.beispielshop.de/?wsvc=View&view=testMode.htm ``` ### Prüfen, ob der Testmodus aktiv ist ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsTestMode.active }} Dieser Inhalt ist nur im Test-Modus sichtbar {{ else}} Dieser Inhalt ist nur im Live-Modus sichtbar {{ /if }} ``` ### Deaktivieren des globalen Testmodus Es kann auch direkt im Onlineshop eine Option angeboten werden, um den Testmodus zu deaktivieren, um wieder in den Onlineshop zu wechseln. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
    ``` Weitere Praxisbeispiele zu Umsetzungen der Testmodus-Seite gibt es hier:\ → [Praxisbeispiele Testmodus](/frontend/praxisbeispiele/testmodus) *** ## Weiterführende Links * [actions - Testmodus](/konfiguration/actions-fehlertexte-e-mails/actions-testmodus) * [Testmodus](/frontend/praxisbeispiele/testmodus) # $wsViews - Aktuelle Informationen abrufen Source: https://dokumentation.websale.de/frontend/referenz/module/wsviews Modul $wsViews: Informationen zur aktuellen Seite abrufen, View-URLs zu anderen Shop-Seiten generieren und SEO-Tags wie hreflang setzen. Mit dem `$wsViews` Modul können Sie auf Informationen zur aktuellen Seite zugreifen und URLs zu anderen Shop-Seiten generieren. Typische Anwendungsfälle sind SEO-Optimierung (Meta-Tags, hreflang), Navigation und bedingte Inhalte basierend auf dem aktuellen Template. In diesem Abschnitt erfahren Sie, wie Sie auf Seitendaten zugreifen und SEO-freundliche URLs erzeugen können. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsViews` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsViews | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "current": { "closedShopRedirected": false, "ctrlName": "...", "info": { }, "name": "...", "paramList": [...], "params": { }, "robotOptions": [...], "status": 200, "getHreflangAutomatic": "ƒ()", "url": "ƒ()" }, "host": "...", "getHreflangManual": "ƒ()", "identifyUrl": "ƒ()", "metaDescription": "ƒ()", "metaTitle": "ƒ()", "setChildUrl": "ƒ()", "url": "ƒ()", "viewUrl": "ƒ()" } ``` Anmerkung: `ƒ()` kennzeichnet eine Funktion. **Variablen und Methoden in der Übersicht** | **Name** | **Rückgabe-Typ** | **Beschreibung** | | -------------------------------- | ---------------- | ---------------------------------------------------------------------------------------------- | | `current` | map | Informationen zur aktuellen Seite. | | `closedShopRedirected` | bool | Prüft, ob eine Weiterleitung von einem geschlossenen Shop erfolgt ist. | | `ctrlName` | string | Name des View-Controllers. | | `getHreflangAutomatic` | function | Gibt die Werte der hreflang Tags der aktuellen Seite aus. | | `info` | map | Zusätzliche Infos vom Controller (z.B. Kategorie, Produkt). | | `name` | string | Name der View-Datei (z.B. `"start.htm"`). | | `paramList` | array | Liste der URL-Parameter mit `name` und `value`. | | `name` | string | Name des Parameters. | | `value` | string | Value des Parameters. | | `params` | map | URL-Parameter als Map (`{name: value}`). | | `robotOptions` | map | Robots-Einstellungen der Seite. | | `status` | number | HTTP-Status-Code (z.B. `200`). | | `host` | string | Gibt die URL der Startseite aus. | | `metaDescription` | string | Meta-Description der aktuellen Seite, Seiten-Beschreibung. | | `metaTitle` | string | Meta Title der aktuellen Seite; Seiten-Titel. | | `url` | string | Gibt die aktuell aufgerufene URL aus. | | `viewUrl` | string | Bildet eine URL zu einer View mithilfe der Angabe eines View-Controllers und seiner Parameter. | | `current.url()` | string | Erzeugt eine SEO-freundliche URL zu einer Shop-Seite. | | `url()` | string | Bildet einen Link zu einer Shop-Seite. | | `viewUrl()` | string | Erzeugt eine URL zu einer Template-Datei. | | `metaTitle()` | string | Gibt den Seitentitel für den Browser-Tab und Suchergebnisse aus. | | `metaDescription()` | string | Gibt die Seitenbeschreibung für Suchergebnisse aus. | | `getHreflangManual()` | array | Gibt manuell konfigurierte hreflang-Einträge aus. | | `current.getHreflangAutomatic()` | array | Gibt die Sprachversionen der aktuellen Seite für hreflang-Tags aus. | *** ## Variablen ### \$wsViews.current Enthält alle Informationen zur aktuell angezeigten Seite. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsViews.current | json }} ``` #### \$wsViews.current.ctrlName Gibt den Namen des View-Controllers aus, der die aktuelle Seite liefert. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} View-Controller: {{= $wsViews.current.ctrlName }} ``` #### \$wsViews.current.closedShopRedirected Gibt aus, ob der Nutzer von einem geschlossenen Shop weitergeleitet wurde. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsViews.current.closedShopRedirected }} // Von geschlossenem Shop weitergeleitet {{ /if }} ``` #### \$wsViews.current.info Gibt kontextspezifische Daten aus, z.B. das aktuelle Produkt auf Produktseiten (`info.product`) oder die Kategorie auf Kategorieseiten (`info.category`). ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Zusätzliche Informationen: {{= $wsViews.current.info}} ``` #### \$wsViews.current.name Gibt den Namen der aktuellen View aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsViews.current.name == "category.htm" }} // Kategorie-Seite {{ /if }} ``` #### \$wsViews.current.paramList Gibt eine Liste der URL-Parameter aus. Jeder Eintrag enthält `name` und `value`. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $myParam in $wsViews.current.paramList }} {{= $myParam.name }}: {{= $myParam.value }} {{ /foreach }} ``` #### \$wsViews.current.params Gibt die URL-Parameter als Map aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsViews.current.params.promoCode }} Promo-Code: {{= $wsViews.current.params.promoCode }} {{ /if }} ``` #### \$wsViews.current.robotOptions Gibt die Robots-Einstellungen der Seite aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Robots: {{= $wsViews.current.robotOptions | json }} ``` #### \$wsViews.current.status Gibt den HTTP-Status-Code der Seite aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Status: {{= $wsViews.current.status }} ``` ### \$wsViews.host Gibt die URL der Shop-Startseite aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Shop-Startseite: {{= $wsViews.host }} ``` *** ## Methoden ### \$wsViews.current.url() Erzeugt eine SEO-freundliche URL zu einer Shop-Seite. Die URL wird automatisch mit sprechenden Pfaden generiert (z.B. `/produkte/beispiel-produkt` statt `?productId=123`). **Signatur**\ `$wsViews.current.url()` **Rückgabe**\ `string` - Aktuelle URL / Pfad. **Beispiel,** das die aktuelle URL ausgibt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Aktuelle URL: {{= $wsViews.current.url() }} ``` ### \$wsViews.url() Bildet einen Link zu einer Shop-Seite (z.B. Produktseite, Kategorieseite). Die URL wird automatisch im SEO-freundlichen Format erzeugt. **Signatur**\ `string $wsViews.url(viewCtrl, params)` **Rückgabe**\ `string` *-* URL/Pfad zur gewünschten Seite.. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ---------- | ------- | ----------- | --------------------------------------------------------------------------------------- | | `viewCtrl` | string | ja | Ziel-Controller/Seitentyp (z.B. `Product, Category`) | | `params` | map | ja | Parameter zum Ergänzen/Überschreiben der URL; der Wert `null` entfernt einen Parameter. | **Beispiel**\ Beispiel, das eine URL zu einer Produktseite erzeugt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsViews.url('Product', {productId: $cProduct.product.id}) }} ``` **Rückgabe-Beispiel:** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} /produkte/beispiel-produkt-12345 ``` ### \$wsViews.viewUrl() Erzeugt eine URL zu einer Template-Datei. **Signatur** `string wsViews.viewUrl(path, params, type)` **Rückgabe**\ `string` - URL zur angegebenen View. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | -------- | ------- | ----------- | ----------------------------------------------------------- | | `path` | string | ja | Pfad zur Template-Datei, z.B. `account/forgotPassword.htm`. | | `params` | map | nein | Zusätzliche Parameter für die URL. | | `type` | string | nein | URL-Typ (z.B. `"absolute"`). | **Beispiel,** das eine URL zur Passwort-vergessen-Seite erzeugt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Passwort vergessen? ``` ### \$wsViews.metaTitle() Gibt den Seitentitel für den Browser-Tab und Suchergebnisse aus. **Signatur**\ `string $wsViews.metaTitle()` **Rückgabe**\ `string` - Seitentitel. **Beispiel,** das den Meta-Titel im HTML-Head setzt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsViews.metaTitle() }} ``` ### \$wsViews.metaDescription() Gibt die Seitenbeschreibung für Suchergebnisse aus. **Signatur**\ `string $wsViews.metaDescription()` **Rückgabe**\ `string` - Seitenbeschreibung. **Beispiel,** das die Meta-Description im HTML-Head setzt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` ### \$wsViews.getHreflangManual() Gibt manuell konfigurierte `hreflang`-Einträge aus. **Signatur**\ `$wsViews.getHreflangManual()` **Rückgabe**\ `array` - Liste mit manuellen Sprachversionen. **Beispiel,** das manuelle `hreflang`-Links ausgibt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $myHref in $wsViews.getHreflangManual() }} {{ /foreach }} ``` ### \$wsViews.current.getHreflangAutomatic() Gibt die Sprachversionen der aktuellen Seite für hreflang-Tags aus. **Signatur**\ `$wsViews.current.getHreflangAutomatic()` **Rückgabe**\ `array` - Liste mit Sprachversionen (`lang`, `href`). **Beispiel,** das automatische hreflang-Links ausgibt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $myHreflang in $wsViews.current.getHreflangAutomatic() }} {{ /foreach }} ``` *** ## Aktionen Für `$wsViews` stehen keine Aktionen zur Verfügung. *** ## Beispiele für URL- und Parameter-Zugriffe ### View-URL & Host ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsViews.current.url() }} ``` ### Template bedingte Ausgaben von Inhalten ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ... {{ if ($wsViews.current.name == "start") }}
    {{ /if }} ... ``` ### Parameter lesen (Liste & gezielte Abfrage) Iteration über alle Parameter: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ...
      {{ for (p in $wsViews.paramList) }}
    • {{= p.name }} = {{= p.value }}
    • {{ end }}
    ... ``` Gezielt prüfen (Beispiel „otp“): ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if ($wsViews.params.otp && $wsViews.params.otp == "required") }}
    Bitte Einmalpasswort eingeben.
    {{ /if }} ``` ### Hreflang & Meta (Kurzbeispiele) ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ... {{= $wsViews.metaTitle() }} {{ for (h in $wsViews.getHreflangAutomatic()) }} {{ end }} {{ for (h in $wsViews.getHreflangManual()) }} {{ end }} ... ```   *** ## Weiterführende Links * [SEO-Metadaten konfigurieren](/konfiguration/seometadata-meta-daten-seo-texte) # $wsVoucher - Gutscheine Source: https://dokumentation.websale.de/frontend/referenz/module/wsvoucher Modul $wsVoucher: eingelöste Gutscheine auflisten, Gesamtwert berechnen und Details zu einzelnen Gutscheinen im Warenkorb und Checkout anzeigen. Mit dem `$wsVoucher` Modul können Sie Gutschein-Daten dynamisch im Frontend verwenden und anzeigen. Sie können eingelöste Gutscheine auflisten, den Gesamtwert berechnen und Details zu einzelnen Gutscheinen laden. In diesem Abschnitt erfahren Sie, wie Sie Gutscheindaten abrufen und im Warenkorb oder Checkout darstellen können. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsVoucher` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsVoucher | json }} ``` **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "vouchers": [...], "totalValue": 0.0, "totalUsedValue": 0.0, "maximumCount": 0, "load": "ƒ()" } ``` **Anmerkung:** `ƒ()` kennzeichnet eine Funktion. **Variablen und Methoden in der Übersicht** | **Name** | **Typ** | **Beschreibung** | | ---------------- | ------- | -------------------------------------------------------------------------------------------------------- | | `vouchers` | array | Liste der Gutscheine, die zum Einlösen vorgemerkt sind. | | `totalValue` | float | Gesamtwert der eingesetzten Gutscheine. | | `totalUsedValue` | float | Bereits genutzter Wert der Gutscheine. | | `maximumCount` | int | Maximale Anzahl der Gutscheine, die gleichzeitig eingelöst werden dürfen.
    `0` = kein Limit gesetzt. | | `load()` | map | Lädt einen Gutschein anhand seiner ID. | *** ## Templates Gutscheindaten können grundsätzlich auf allen Templates geladen und angezeigt werden. Eine Eingabe bzw. Einlösung eines Gutscheincodes ist im gesamten Shop möglich. Am sinnvollsten erfolgt dies jedoch innerhalb des Bestellprozesses oder im Warenkorb. *** ## Variablen ### \$wsVoucher.vouchers Gibt eine Liste aller Gutscheine aus, die der Kunde im aktuellen Warenkorb eingelöst hat. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $myVoucher in $wsVoucher.vouchers }} Gutschein: {{= $myVoucher.id }} – Wert: {{= $myVoucher.value | currency }} {{ /foreach }} ``` ### \$wsVoucher.totalValue Gibt den Gesamtwert der eingesetzten Gutscheine aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Gutscheinwert: {{= $wsVoucher.totalValue | currency }} ``` ### \$wsVoucher.totalUsedValue Gibt den bereits vom Warenkorb abgezogenen Gutscheinwert aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Bereits eingelöst: {{= $wsVoucher.totalUsedValue | currency }} ``` ### \$wsVoucher.maximumCount Gibt die maximale Anzahl der Gutscheine zurück, die ein Kunde gleichzeitig einlösen darf. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Eingelöst: {{= len($wsVoucher.vouchers) }} von {{= $wsVoucher.maximumCount }} ``` *** ## Methoden ### \$wsVoucher.load() Lädt einen Gutschein anhand seiner ID. **Signatur**
    `$wsVoucher.load(id)` **Rückgabe**
    `Map` - Voucher-Map mit den Gutschein-Daten. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | -------- | ------- | ----------- | ------------------ | | `id` | string | ja | ID des Gutscheins. | **Beispiel,** das einen Gutschein lädt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myVoucher = $wsVoucher.load("GUTSCHEIN123") }} Wert: {{= $myVoucher.value | currency }} ``` Mit Verwendung der Funktion `$wsVoucher.load()` stehen verschiedene Variablen zur Verfügung, um Gutschein-Daten abzurufen und auszugeben. Nachfolgend eine Übersicht, welche Variablen verfügbar sind. ### **Gutschein-Daten (Rückgabe von \$wsVoucher.load() )** Zunächst ist es notwendig, die Map mit den Gutschein-Daten, wie im obigen Beispiel dargestellt, einer lokalen Variable zuzuweisen. Diese kann anschließend an verschiedenen Stellen im Template verwendet werden. **JSON-Ausgabe** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "...", "value": 0.0, "currency": "...", "taxId": "...", "usedValue": 0.0, "percentValue": 0.0, "absoluteValue": 0.0, "validFrom": "...", "validUntil": "..." } ``` **Variablen in der Übersicht** | **Variable** | **Typ** | **Beschreibung** | | --------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `id` | string | Gutschein-ID. | | `value` | float | Wert des Gutscheins. | | `currency` | string | Währung des Gutscheins. | | `taxId` | string | Steuersatz-ID des Gutscheins. | | `usedValue` | float | Bereits eingelöster Wert des Gutscheins. | | `percentValue` | float | Bei prozentualen Gutscheinen ist `percentValue` gefüllt (z.B. 10 für 10%), bei Festbetrags-Gutscheinen ist `absoluteValue` gefüllt (z.B. 5.00 für 5€). | | `absoluteValue` | float | Bei prozentualen Gutscheinen ist `percentValue` gefüllt (z.B. 10 für 10%), bei Festbetrags-Gutscheinen ist `absoluteValue` gefüllt (z.B. 5.00 für 5€). | | `validFrom` | string | Gültig ab (Datum). | | `validUntil` | string | Gültig bis (Datum). | *** ## Aktionen Aktionen zu diesem Modul, die Änderungen auslösen, sind separat im Kapitel “Aktionen” dokumentiert: [Voucher](/frontend/referenz/aktionen/voucher) *** ## Beispiel für Anzeige von Gutscheindaten ### Wert des Gutscheins In diesem Beispiel wird der Wert des Gutscheins angezeigt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Voucher Value: {{= $voucher.value }} ``` ### Gutschein-Typ: Prozentualer oder Festbetrag In diesem Beispiel wird geprüft und angezeigt, ob der Gutschein einen prozentualen Rabatt oder einen festen Betrag gewährt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Rabatt Typ: {{= $voucher.percentValue | ifNull("Percentage Value is null")}} {{= $voucher.absoluteValue | ifNull("absolute value is nulll")}} ``` ### Gültigkeitsdatum des Gutscheins In diesem Beispiel werden das Start- und Enddatum der Gültigkeit eines Gutscheins angezeigt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Gültig ab: {{= $voucher.validFrom | dateFmt("%d.%m.%Y") }} Gültig bis: {{= $voucher.validUntil | dateFmt("%d.%m.%Y") }} ``` ### Währung des Gutscheins In diesem Beispiel wird die Währung angezeigt, in der der Gutschein ausgestellt wurde. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Währung: {{= $voucher.currency }} ``` ### Restbetrag eines Gutscheins anzeigen In diesem Beispiel wird angezeigt, wie viel Restbetrag ein teilgenutzter Gutschein noch hat. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Restbetrag: {{= ($voucher.value - $voucher.usedValue) | currency }} ``` ### Gültigkeit eines Gutscheins prüfen In diesem Beispiel wird überprüft, ob der Gutschein grundsätzlich gültig ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $voucherAddAction.success }} Gutschein erfolgreich in den Warenkorb gelegt. {{ /if }} ``` ### Formular nur anzeigen, bis die maximale Anzahl an Gutscheinen eingelöst ist Das Formular erscheint nur, wenn die Anzahl bereits eingelöster Gutscheine kleiner ist als das konfigurierte Limit. Ist das Limit erreicht, wird das Formular ausgeblendet und der Kunde erhält einen Hinweis. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if len($wsVoucher.vouchers) < $wsVoucher.maximumCount }}
    {{ /if }} ``` Weitere Praxisbeispiele zum Thema Gutscheine finden Sie [hier](/gutscheine). *** ## Weiterführende Links * [Einstellungen für Gutscheine](https://dokumentation.websale.de/konfiguration/checkout-bestellablauf#checkout-voucher-einstellungen-für-gutscheine) * [Praxisbeispiele für Gutscheine](/gutscheine) * [Fehlertexte zu wirkungslosen Gutscheinen](/konfiguration/checkout-bestellablauf#checkout-vouchererrors-fehlertexte-zu-wirkungslosen-gutscheinen) * [\$wsCheckout.ineffectiveVoucherErrors](/frontend/referenz/module/wscheckout) - Fehlerliste zu Gutscheinen, die im Warenkorb nicht greifen # $wsWatchList - Merklisten Source: https://dokumentation.websale.de/frontend/referenz/module/wswatchlist Modul $wsWatchList für Merklisten: prüfen, Produkte hinzufügen oder entfernen und Wunschlisten des Nutzers im Frontend oder Warenkorb anzeigen. Mit dem `$wsWatchList` Modul können Sie auf die Merklisten (Wunschlisten) des Nutzers zugreifen und diese im Frontend anzeigen. Sie können prüfen, ob Produkte auf einer Merkliste sind, Produkte hinzufügen oder entfernen und die Merkliste im Warenkorb darstellen. In diesem Abschnitt erfahren Sie, wie Sie Merklisten laden und verwalten können. *** ## Modulübersicht **Beispiel / Ausschnitt über** `$wsWatchList` ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $wsWatchList | json }} ``` **JSON-Ausgabe:** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "watchLists": [ { "watchListId": "...", "watchListName": "..." } ], "countWatchListsWithProduct": "ƒ()", "isProductOnWatchList": "ƒ()", "loadWatchList": "ƒ()", "loadWatchListItemId": "ƒ()" } ``` **Anmerkung:** `ƒ()` kennzeichnet eine Funktion. **Variablen und Methoden in der Übersicht** | **Name** | **Rückgabe-Typ** | **Beschreibung** | | ------------------------------ | ---------------- | --------------------------------------------------------------------------- | | `watchLists` | array | Gibt eine Liste mit allen Merklisten des Nutzers aus. | | `[$i].watchListId` | string | Gibt die ID der Merkliste aus. | | `[$i].watchListName` | string | Gibt den Namen der Merkliste aus. | | `loadWatchList()` | map | Lädt eine Merkliste anhand ihrer ID. | | `isProductOnWatchList()` | bool | Prüft, ob ein Produkt auf einer bestimmten Merkliste vorhanden ist. | | `countWatchListsWithProduct()` | int | Gibt die Anzahl der Merklisten aus, auf denen ein bestimmtes Produkt liegt. | | `loadWatchListItemId()` | string | Gibt die ID des Merklisten-Eintrags für ein bestimmtes Produkt zurück. | *** ## Templates Merkliste-Produkte werden über `$wsWatchList` im Template `basket.htm` geladen. Dort können sie in den Warenkorb gelegt oder aus der Merkliste entfernt werden. Zusätzlich ist es möglich, die Merkliste im Header oder im Offcanvas-Flyout anzuzeigen. *** ## Variablen ### \$wsWatchList.watchLists Gibt eine Liste aller Merklisten des Nutzers aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $myWatchlistVariable in $wsWatchList.watchLists }} {{= $myWatchlistVariable.watchListId }} - {{= $myWatchlistVariable.watchListName }} {{ /foreach }} ``` *** ## Methoden ### \$wsWatchList.loadWatchList() Lädt eine Merkliste anhand ihrer ID. **Signatur**\ `$wsWatchList.loadWatchList(watchlistId)` **Rückgabe**\ `map` - WatchList-Map mit allen Daten. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ------------- | ------- | ----------- | ----------------- | | `watchlistId` | string | ja | ID der Merkliste. | **Beispiel,** das die Standard-Merkliste lädt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myWatchList = $wsWatchList.loadWatchList("watchlist_1_default") }} ``` Mit Verwendung der Funktion `$wsWatchList.loadWatchList()` stehen verschiedene Variablen zur Verfügung, um weitere Daten zur Merkliste abzurufen und auszugeben. Nachfolgend eine Übersicht, welche Variablen verfügbar sind. ### Merklisten-Daten (Rückgabe von \$wsWatchList.loadWatchList() ) Zunächst ist es notwendig, die Map mit den Merklisten-Daten, wie im obigen Beispiel dargestellt, einer lokalen Variable zuzuweisen. Diese kann anschließend an verschiedenen Stellen im Template verwendet werden. **JSON-Ausgabe der Variablen:** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "...", "watchListName": "...", "items": [ { "id": "...", "freeFields": { }, "product": { ... } } ] } ``` **Variablen in der Übersicht** | **Variable** | **Typ** | **Beschreibung** | | ----------------- | ------- | ---------------------------------------------------------------------------------- | | `id` | string | ID der Merkliste. | | `watchListName` | string | Name der Merkliste. | | `items` | array | Liste der Produkte auf der Merkliste. | | `[$i].id` | string | ID des Merklisten-Eintrags. | | `[$i].freeFields` | map | Benutzerdefinierte Felder zum Merklisten-Eintrag (z.B. Notizen, gewünschte Menge). | | `[$i].product` | map | Produktdaten (Map “Product”). | ### \$wsWatchList.isProductOnWatchList() Prüft, ob ein Produkt auf einer bestimmten Merkliste vorhanden ist. **Signatur**\ `$wsWatchList.isProductOnWatchList(watchlistId, productId)` **Rückgabe**\ `bool` - `true`, wenn das Produkt auf der Merkliste ist, sonst `false`. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ------------- | ------- | ----------- | ----------------- | | `watchlistId` | string | ja | ID der Merkliste. | | `productId` | string | ja | ID des Produkts. | **Beispiel,** das prüft, ob ein Produkt auf der Merkliste ist. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsWatchList.isProductOnWatchList("watchlist_1_default", $product.id) }} Auf der Merkliste {{ /if }} ``` ### \$wsWatchList.countWatchListsWithProduct() Gibt die Anzahl der Merklisten aus, auf denen ein bestimmtes Produkt liegt. **Signatur**\ `$wsWatchList.countWatchListsWithProduct(productId)` **Rückgabe**\ `int` - Anzahl der Merklisten, auf denen das Produkt liegt. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ----------- | ------- | ----------- | ---------------- | | `productId` | string | ja | ID des Produkts. | **Beispiel,** das die Anzahl der Merklisten mit einem Produkt ausgibt: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Auf {{= $wsWatchList.countWatchListsWithProduct($product.id) }} Merklisten ``` ### \$wsWatchList.loadWatchListItemId() Gibt die ID des Merklisten-Eintrags für ein bestimmtes Produkt zurück. Diese ID wird benötigt, um das Produkt von der Merkliste zu entfernen. **Signatur**\ `$wsWatchList.loadWatchListItemId(watchlistId, productId)` **Rückgabe**\ `string` - ID des Merklisten-Eintrags. **Parameter** | **Name** | **Typ** | **Pflicht** | **Beschreibung** | | ------------- | ------- | ----------- | ----------------- | | `watchlistId` | string | ja | ID der Merkliste. | | `productId` | string | ja | ID des Produkts. | **Beispiel,** das die Eintrag-ID eines Produkts lädt. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myItemId = $wsWatchList.loadWatchListItemId("watchlist_1_default", $product.id) }} ``` *** ## Aktionen Aktionen zu diesem Modul, die Änderungen auslösen, sind separat im Kapitel “Aktionen” dokumentiert: [Watchlist](/frontend/referenz/aktionen/watchlist) *** ## Beispiele für die Anzeige von Merkliste-Informationen ### Prüfen, ob die Merkliste Produkte enthält. In diesem Beispiel wird geprüft, ob Produkte auf der Merkliste enthalten sind, und gibt die Anzahl der Produkte aus. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsWatchList.items }}

    Es gibt {{= $wsWatchList.items | len }} Produkte auf der Merkliste

    {{ /if }} ``` ### Eigenschaften der Produkte auf der Merkliste Nachdem die Daten der Merkliste geladen und einer Variable zugewiesen wurden, können Sie diese flexibel ausgeben. Die Zuweisung kann wie folgt erfolgen: ### Produktdaten anzeigen In diesem Beispiel werden die üblichen Produktinfos ausgegeben, wie zum Beispiel der Produktname, Preis und Bild. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsWatchList.items }} {{ foreach $product in $wsWatchList.items }} {{= $watchListItem.product.name }}

    Produktname: {{= $watchListItem.product.name }}

    Preis: {{= $watchListItem.product.price }}

    {{ /foreach }} {{ /if }} ``` ### Produktvarianten Anzeigen In diesem Beispiel wird geprüft, ob sich eine Produktvariante auf der Merkliste befindet. Im positiven Fall werden die Eigenschaften der Produktvariante ausgelesen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{if $wsWatchList.items}} {{ foreach $watchListItem in $wsWatchList.items }} ... {{ if $watchListItem.product.variantSelection }} {{ foreach $varAttr in $watchListItem.product.variantSelection | keys }}

    {{= $varAttr}}: {{= $watchListItem.product.variantSelection[$varAttr] }}

    {{ /foreach }} {{ /if }} {{ /foreach }} ... {{/if}} ``` ### Freifelder auf der Merkliste zeigen In diesem Beispiel wird geprüft, ob das Produkt Freifelder besitzt, wie zum Beispiel Herkunftsland oder Gewicht, und zeigt diese an. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{if $wsWatchList.items}} {{ foreach $watchListItem in $wsWatchList.items }} ... {{ if $watchListItem.freeFields }} {{ foreach $freeFieldName in $watchListItem.freeFields | keys }}

    {{= $freeFieldName}}: {{= $watchListItem.freeFields[$freeFieldName] }}

    {{ /foreach }} {{ /if }} {{ /foreach }} ... {{/if}} ``` ### Produkt in den Warenkorb legen In diesem Beispiel wird gezeigt wie ein Produkt aus der Merkliste in den Warenkorb gelegt wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{if $wsWatchList.items}} {{ foreach $watchListItem in $wsWatchList.items }} ... {{ var $basketItemAdd = $wsActions.create("BasketItemAdd", tag=$watchListItem.id) }} {{ if $basketItemAdd.error }} Es sind Fehler aufgetreten: {{ foreach $error in $basketItemAdd.errors }} {{ if $error.text }}

    {{= $error.text }}

    {{ else }}

    {{= $error.code }}

    {{ /if }} {{ /foreach }} {{ /if }}
    {{ foreach $freeFieldName in $watchListItem.freeFields | keys }} {{ /foreach }}
    {{ /foreach }} {{ else }} ... {{/if}} ``` ### Produkt aus der Merkliste löschen In diesem Beispiel wird gezeigt wie ein Produkt aus der Merkliste gelöscht wird. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{if $wsWatchList.items}} {{ foreach $watchListItem in $wsWatchList.items }} ... {{ var $watchListItemDelete = $wsActions.create("WatchListItemDelete", tag=$watchListItem.id) }} {{ if $watchListItemDelete.error }} Es sind Fehler aufgetreten: {{ foreach $error in $watchListItemDelete.errors }} {{ if $error.text }}

    {{= $error.text }}

    {{ else }}

    {{= $error.code }}

    {{ /if }} {{ /foreach }} {{ /if }}
    {{ /foreach }} {{ else }} ... {{/if}} ``` Weitere Praxisbeispiele zur Verwendung der Merkliste und Merklisten-Funktionen befinden sich hier: → [Praxisbeispiele Merkliste](/frontend/praxisbeispiele/memolist-offcanvas) *** ## Weiterführende Links * [Memolist (offcanvas)](/frontend/praxisbeispiele/memolist-offcanvas) * [\$wsBasket](/frontend/referenz/module/wsbasket) # Operatoren Source: https://dokumentation.websale.de/frontend/referenz/operatoren Operatoren der Template-Sprache: Zugriff, Mathematik, Vergleich, Logik und der in-Operator zum Arbeiten mit Werten, Listen und Maps. Operatoren werden in der Template-Sprache verwendet, um auf Werte zuzugreifen, Werte zu berechnen, Inhalte zu vergleichen oder Bedingungen zu verknüpfen. Sie sind ein grundlegender Bestandteil vieler Template-Ausdrücke, zum Beispiel bei Ausgaben, Bedingungen oder beim Arbeiten mit Listen und Maps. Im Unterschied zu Funktionen werden Operatoren nicht als Aufruf mit Klammern geschrieben, sondern direkt innerhalb eines Ausdrucks verwendet. Die vorhandene Operatoren-Referenz behandelt dazu insbesondere Zugriffs-, mathematische, Vergleichs-, logische sowie den Containment-Operator `in`. *** ## Grundlagen ### **Schreibweise** Operatoren werden direkt innerhalb eines Ausdrucks verwendet. Sie können sowohl in einer Ausgabe als auch in einer Variablenzuweisung oder in einer Bedingung vorkommen. Damit das Ergebnis eines Ausdrucks direkt im Template ausgegeben wird, wird die Ausgabe-Schreibweise verwendet: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= }} ``` Ein Ausdruck kann auch zunächst einer eigenen Variablen zugewiesen werden, um ihn später weiterzuverwenden: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myVariable = }} ``` Die vorhandenen Referenzseiten zeigen genau dieses Muster bereits für Funktionsaufrufe, Variablen und Operator-Ausdrücke.   ### Operatoren in Ausgaben und Bedingungen Operatoren werden besonders häufig in diesen Situationen verwendet: * beim Zugriff auf Werte in Maps oder Listen * bei Berechnungen * bei Vergleichen in `if`-Bedingungen * beim Verknüpfen mehrerer Bedingungen * beim Prüfen, ob ein Wert in einer Liste oder Map enthalten ist **Beispiele:** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $myProduct.name }} {{= $myPrice * $quantity }} {{= $myProductStock > 0 }} {{= $myPrice > 10 and $myProductStock > 0 }} {{= "red" in $myAvailableColors }} ``` Die Operatoren-Seite dokumentiert dafür bereits `.` und `[]` für Zugriffe, mathematische Operatoren, Vergleichsoperatoren, logische Operatoren sowie `in`.     ### Reihenfolge und Klammern Sobald mehrere Operatoren in einem Ausdruck kombiniert werden, sollte mit Klammern gearbeitet werden, um die gewünschte Reihenfolge eindeutig zu machen. Das erhöht nicht nur die Lesbarkeit, sondern verhindert auch Missverständnisse bei komplexeren Bedingungen. Beispiel: `{{= ($myPrice > 0 and $stock > 0) or $myIsBackorderAllowed }}` Empfehlung: * Einfache Ausdrücke können direkt geschrieben werden. * Bei gemischten Vergleichen und logischen Verknüpfungen sollten Klammern verwendet werden. * Besonders bei `and`, `or` und `not` ist eine klare Struktur wichtig.   ***   ## Liste der Operatoren   ### Punkt-Operator `.` Der Punkt-Operator wird verwendet, um auf ein Attribut einer Map zuzugreifen. Die bestehende Operatoren-Seite beschreibt den Punkt-Operator als Standardzugriff auf Attribute eines Objekts und zeigt zugleich, dass er bei Listenindizes nicht funktioniert. Anwendungsbeispiel\ Typisch ist der Zugriff auf Produktdaten, Kundendaten oder andere strukturierte Werte. Schreibweise ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $myMap.key }} ``` Beispiel – Produktname ausgeben ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $myProduct.name }} ``` Beispiel – Lieferland aus einer Bestelladresse ausgeben ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $order.shippingAddress.country }} ``` Hinweis: Für numerische Listenindizes ist der Punkt-Operator nicht geeignet. Beispiel – funktioniert nicht bei einer Liste ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myList = [4, 3, 2, 1] }} {{= $myList.2 }} ``` Ausgabe ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Keine Ausgabe ```     ### Index-Operator `[]` Der Index-Operator wird verwendet, um auf Werte in Listen oder Maps zuzugreifen. Bei Maps wird der Schlüssel in eckigen Klammern angegeben. Bei Listen wird der numerische Index verwendet. Laut bestehender Doku kann im Index-Operator auch eine Variable verwendet werden. Anwendungsbeispiel\ Sinnvoll bei dynamischen Schlüsseln oder beim Zugriff auf ein bestimmtes Listenelement. Schreibweise ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $myObject["key"] }} {{= $myList[0] }} ``` Beispiel – auf ein Feld in einer Map zugreifen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $myProduct["price"] }} ``` Beispiel – erstes Element einer Liste ausgeben ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myList = [4, 3, 2, 1] }} {{= $myList[0] }} ``` Ausgabe ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 4 ``` Beispiel – dynamischen Schlüssel verwenden ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $fieldName = "price" }} {{= $myProduct[$fieldName] }} ``` Hinweis: Listenindizes beginnen bei `0`.   ### Additionsoperator `+` Der Operator `+` wird verwendet, um numerische Werte zu addieren. Auf der aktuellen Funktionsseite wird zusätzlich dokumentiert, dass `+` auch zum Zusammenfügen von Strings sowie zum Vereinen von Listen verwendet werden kann. Das widerspricht der älteren Operatoren-Seite; dieser Entwurf folgt deshalb der neueren Funktionsseite. **Anwendungsbeispiel**\ Verwendbar für Berechnungen, aber auch zum Zusammensetzen von Texten oder zum Zusammenführen von Listen. Schreibweise ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= value1 + value2 }} ``` Beispiel – zwei Zahlen addieren ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= 10 + 1 }} ``` Ausgabe ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 11 ``` Beispiel – Artikelnummer aus Präfix und ID zusammensetzen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $prefix = "ART-" }} {{ var $productId = "10452" }} {{= $prefix + $productId }} ``` Ausgabe ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ART-10452 ``` Beispiel – Zahl in einen Text einfügen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $quantity = 3 }} {{= "Anzahl Artikel im Warenkorb: " + str($quantity) }} ``` Beispiel – zwei Listen zusammenführen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $listA = ["red", "green"] }} {{ var $listB = ["blue"] }} {{= $listA + $listB | json }} ``` Hinweis: Beim Zusammenfügen von Texten müssen nicht-string Werte gegebenenfalls zuerst mit `str()` in einen String umgewandelt werden.   ### Subtraktionsoperator `-` Der Operator `-` subtrahiert einen Wert von einem anderen Wert. Die Operatoren-Seite dokumentiert `-` als einen der mathematischen Grundoperatoren. Anwendungsbeispiel\ Nützlich für Preisunterschiede, Rabatte oder Restmengen. Schreibweise ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= value1 - value2 }} ``` Beispiel – Preisnachlass berechnen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $regularPrice = 99.95 }} {{ var $salePrice = 79.95 }} {{= $regularPrice - $salePrice }} ``` Ausgabe ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 20 ``` Beispiel – Restbestand nach Abzug berechnen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $stock = 15 }} {{ var $reserved = 4 }} {{= $stock - $reserved }} ``` Ausgabe ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 11 ```     ### Multiplikationsoperator `*` Der Operator `*` multipliziert zwei numerische Werte. Er ist Teil der auf der Operatoren-Seite dokumentierten mathematischen Operatoren. Anwendungsbeispiel\ Typisch für Mengen- und Preisberechnungen. Schreibweise ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= value1 * value2 }} ``` Beispiel – Zwischensumme berechnen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $unitPrice = 19.99 }} {{ var $quantity = 3 }} {{= $unitPrice * $quantity }} ``` Beispiel – Verpackungseinheiten berechnen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $boxes = 4 }} {{ var $itemsPerBox = 6 }} {{= $boxes * $itemsPerBox }} ``` Ausgabe ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 24 ```     ### Divisionsoperator `/` Der Operator `/` dividiert einen numerischen Wert durch einen anderen numerischen Wert. Auch dieser Operator ist in der vorhandenen Mathe-Übersicht dokumentiert. Anwendungsbeispiel\ Hilfreich bei Durchschnittswerten, Anteilen oder Umrechnungen. Schreibweise ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= value1 / value2 }} ``` Beispiel – Durchschnittspreis berechnen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $sum = 90 }} {{ var $count = 3 }} {{= $sum / $count }} ``` Ausgabe ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 30 ``` Beispiel – Teilmenge berechnen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= 7.5 / 3 }} ``` Ausgabe ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 2.5 ``` Hinweis\ Bei Divisionen sollte sichergestellt werden, dass der Divisor nicht `0` ist.     ### Modulo-Operator `%` Der Modulo-Operator `%` gibt den Rest einer Division zurück. Die Operatoren-Seite nennt `%` ausdrücklich als Modulo-Operator. Anwendungsbeispiel\ Nützlich, um gerade und ungerade Werte zu prüfen oder Rasterlogik in Listen umzusetzen. Schreibweise ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= value1 % value2 }} ``` Beispiel – prüfen, ob eine Zahl gerade ist ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= 8 % 2 == 0 }} ``` Ausgabe ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} true ``` Beispiel – jedes dritte Element in einer Liste markieren\ Da die Template Engine keine automatische Zählervariable in Schleifen bereitstellt, wird ein eigener Zähler mitgeführt (siehe [Schleifenzähler](/frontend/referenz/loops#schleifenzähler)). ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $index = 0 }} {{ foreach $product in $productList }} {{ if $index % 3 == 0 }}
    {{ /if }} {{ var $index = $index + 1 }} {{ /foreach }} ```     ### Gleichheitsoperator `==` Der Operator `==` prüft, ob zwei Werte gleich sind. Vergleichsoperatoren liefern laut bestehender Referenz immer einen booleschen Wert, also `true` oder `false`. Anwendungsbeispiel\ Verwendbar für Statusabfragen, Länderprüfungen oder Template-Logik. Schreibweise ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= value1 == value2 }} ``` Beispiel – Land prüfen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $countryCode == "DE" }} ``` Beispiel – Preis mit Maximalwert vergleichen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $maxPrice = 10.00 }} {{ var $price = 10.00 }} {{= $price == $maxPrice }} ``` Ausgabe ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} true ```     ### Ungleichheitsoperator `!=` Der Operator `!=` prüft, ob zwei Werte ungleich sind. Er gehört ebenfalls zu den auf der Operatoren-Seite dokumentierten Vergleichsoperatoren. Anwendungsbeispiel\ Nützlich, wenn ein Wert ausdrücklich nicht einem bestimmten Zustand entsprechen darf. Schreibweise ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= value1 != value2 }} ``` Beispiel – nur anzeigen, wenn ein Kunde nicht gesperrt ist ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $customer.status != "blocked" }} ```     ### Kleiner als `<` Der Operator `<` prüft, ob der linke Wert kleiner als der rechte Wert ist. Vergleichsoperatoren sind laut aktueller Operatoren-Seite für solche Wertvergleiche vorgesehen. Beispiel – Preislimit prüfen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $price < 50 }} ```     ### Größer als `>` Der Operator `>` prüft, ob der linke Wert größer als der rechte Wert ist. Beispiel – Mindestbestellwert prüfen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $cartTotal > 100 }} ```     ### Kleiner oder gleich `<=` Der Operator `<=` prüft, ob ein Wert kleiner oder gleich einem anderen Wert ist. Beispiel – Bestand prüfen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $score >= 80 }} ```     ### Größer oder gleich `>=` Der Operator `>=` prüft, ob ein Wert größer oder gleich einem anderen Wert ist. Beispiel – Mindestalter oder Schwellenwert prüfen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $score >= 80 }} ```     ### Logisches `and` Der Operator `and` verknüpft zwei Bedingungen. Das Ergebnis ist nur dann `true`, wenn **beide** Bedingungen erfüllt sind. Genau dieses Verhalten ist auf der Operatoren-Seite mit Beispielen beschrieben. Anwendungsbeispiel\ Sinnvoll, wenn mehrere Voraussetzungen gleichzeitig erfüllt sein müssen. Schreibweise ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= condition1 and condition2 }} ``` Beispiel – Produkt nur anzeigen, wenn Preis gültig und Bestand vorhanden ist ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $price > 0 and $inventory > 0 }} ``` Beispiel – Kaufbutton nur für aktive Produkte mit Bestand ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $product.active and $product.stock > 0 }} {{ /if }} ```     ### Logisches `or` Der Operator `or` verknüpft zwei Bedingungen. Das Ergebnis ist `true`, wenn **mindestens eine** der Bedingungen erfüllt ist. `or` gehört laut bestehender Referenz zu den logischen Operatoren. Anwendungsbeispiel\ Geeignet für alternative Freigaben oder Sonderfälle. Schreibweise ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $inventory > 0 or $allowPreorder }} ``` Beispiel – Produkt anzeigen, wenn Bestand vorhanden oder Vorbestellung erlaubt ist ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $inventory > 0 or $allowPreorder }} ```     ### Logisches `not` Der Operator `not` kehrt den Wahrheitswert eines Ausdrucks um. Auch `not` ist Teil der auf der Operatoren-Seite dokumentierten logischen Operatoren. Anwendungsbeispiel\ Hilfreich, wenn geprüft werden soll, dass eine Bedingung **nicht** erfüllt ist. Schreibweise ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= not condition }} ``` Beispiel – nur anzeigen, wenn der Benutzer nicht eingeloggt ist ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if not $isLoggedIn }} Jetzt anmelden {{ /if }} ``` Beispiel – Meldung anzeigen, wenn kein Bestand vorhanden ist ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if not ($inventory > 0) }}

    Aktuell nicht verfügbar

    {{ /if }} ```     ### Containment-Operator `in` Der Operator `in` prüft, ob der linke Wert im rechten Objekt enthalten ist. Die bestehende Operatoren-Seite dokumentiert `in` ausdrücklich als Containment-Operator und zeigt als Beispiel `1 in [1, 2, 3]`. Anwendungsbeispiel\ Sinnvoll für Länderlisten, erlaubte Werte, Farbauswahlen oder Whitelists. Schreibweise ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= value in collection }} ``` Beispiel – prüfen, ob eine Farbe verfügbar ist ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= "red" in ["red", "green", "blue"] }} ``` Ausgabe ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} true ``` Beispiel – Land gegen erlaubte Länderliste prüfen ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $allowedCountries = ["DE", "AT", "CH"] }} {{= $countryCode in $allowedCountries }} ``` # Optionen Source: https://dokumentation.websale.de/frontend/referenz/optionen Template-Optionen definieren. Mit Optionen definieren Sie im Template Einstellungen fest, die anschließend im Admin-Interface pflegbar sind, ohne dass das Template erneut angepasst werden muss. So können Sie beispielsweise steuern, ob das Icon einer Zahlungsart im Footer angezeigt wird. Eine Option durchläuft immer denselben Ablauf: definieren → im Admin pflegen → im Template lesen. Diese Seite beschreibt das Definieren. Das Auslesen der gepflegten Werte übernimmt das Modul [\$wsOptions](/frontend/referenz/module/ws-options-template-optionen). *** ## Grundlagen ### Schreibweise Eine Option wird mit der Anweisung `option`, einem eindeutigen Namen und den Angaben hinter `with` definiert: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ option "stringValue" with {"type": "String"} }} ``` Definiert eine Option mit dem Namen `stringValue` vom Typ `String`. Im Admin-Interface entsteht dadurch ein Textfeld; der dort eingetragene Wert wird im Template über `$wsOptions.get("stringValue")` ausgegeben. Jede Option hat genau einen [Typ](#optionstypen), der die Eingabemaske im Admin-Interface bestimmt. ### Eindeutigkeit und Lebenszyklus Jede Option darf nur einmal definiert werden. Werden zwei Optionen mit demselben Namen in unterschiedlichen Templates oder an unterschiedlichen Stellen desselben Templates definiert, entsteht ein Fehler. Die definierten Optionen stehen zur Verfügung, nachdem die Templates erfolgreich kompiliert wurden. Werden Optionen aus dem Template entfernt, verschwinden sie erst nach einer erneuten Kompilierung aus dem Admin-Interface. ### Nur statische Angaben Bei der Definition sind ausschließlich statische Angaben möglich, es dürfen beispielsweise keine Variablen, Operatoren oder Funktionen verwendet werden. Die folgenden Beispiele sind daher **nicht möglich**: | **Beispiel** | **Warum ungültig** | | ------------------------------------------------------------------------- | ------------------------------------------------- | | `{{ var $name = "invalidOption1"; option $name with {"type": "String" }}` | Variablen sind als Optionsname nicht erlaubt. | | `{{ var $type = "String"; option "invalidOption2" with {"type": $type }}` | Variablen sind auch in den Angaben nicht erlaubt. | | `{{ option "invalidOption3" with {"type": "Str" + "ing" }}` | Operatoren sind nicht erlaubt. | | `{{ option upper("invalidOption4") with {"type": "String" }}` | Funktionen sind nicht erlaubt. | ### Anzeigelabel und Beschreibung Anzeigelabel und Beschreibung einzelner Optionen lassen sich im Admin-Interface bzw. über die REST-API bearbeiten. Sie dienen ausschließlich der Anzeige und haben keine weitere Funktion. *** ## Optionstypen Jede Option hat einen Typ, der die Eingabemaske im Admin-Interface bestimmt. ### String Wird im Admin-Interface als Textfeld dargestellt. **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ option "freeShippingHint" with {"type": "String"} }} ``` Im Admin-Interface entsteht dadurch ein Textfeld, in das ein Redakteur einen Hinweis zur kostenlosen Lieferung einträgt (z. B. „Versandkostenfrei ab 50 €"). Im Template gibt `$wsOptions.get("freeShippingHint")` anschließend genau diesen Text aus. *** ### Bool Wird im Admin-Interface als An/Aus-Schalter dargestellt. Geeignet, um beispielsweise ein Verhalten oder ein Anzeigeelement ein- oder auszuschalten. **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ option "showTrustBadges" with {"type": "Bool"} }} ``` Im Admin-Interface entsteht dadurch ein An/Aus-Schalter. Steht er auf „An", liefert `$wsOptions.get("showTrustBadges")` den Wert `true`, andernfalls `false`. Passend, um beispielsweise die Trust-Badges im Template gezielt ein- oder auszublenden. *** ### Int Erwartet eine ganze Zahl. Optional lassen sich über `min` und `max` Wertgrenzen festlegen. **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ option "productsPerRow" with {"type": "Int", "min": 2, "max": 6} }} ``` Im Admin-Interface entsteht dadurch ein Zahlenfeld, das nur ganze Zahlen von 2 bis 6 akzeptiert. Trägt ein Redakteur `4` ein, liefert `$wsOptions.get("productsPerRow")` den Wert `4` - beispielsweise um vier Produkte pro Reihe anzuzeigen. *** ### Float Erwartet eine Kommazahl. Wie bei `Int` lassen sich optional `min` und `max` angeben. **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ option "minRatingForBadge" with {"type": "Float", "min": 0, "max": 5} }} ``` Im Admin-Interface entsteht dadurch ein Eingabefeld für eine Kommazahl von 0 bis 5. Trägt ein Redakteur `4.5` ein, liefert `$wsOptions.get("minRatingForBadge")` diesen Wert, beispielsweise als Mindestbewertung, ab der ein „Top bewertet"-Badge erscheint. *** ### Enum Erlaubt die Auswahl aus einer vordefinierten Liste. Die erlaubten Werte werden über `values` festgelegt. **Beispiel** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ option "teaserLayout" with {"type": "Enum", "values": ["grid", "list", "slider"]} }} ``` Im Admin-Interface entsteht dadurch ein Auswahlfeld mit den drei Werten `grid`, `list` und `slider`. Wählt ein Redakteur `slider`, liefert `$wsOptions.get("teaserLayout")` den Wert `slider`, beispielsweise um die Teaser als Slider statt als Raster darzustellen. *** ## Optionen an Konfigurationen binden Mit `attachTo` binden Sie eine Option an einen Konfigurationsknoten, z. B. `payment.payment` für die Zahlungsarten: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ option "showPaymentIconInFooter" with {"type": "Bool", "attachTo": "payment.payment"} }} ``` Das hat zwei Auswirkungen: * Die Einstellung lässt sich im Admin-Interface direkt in der jeweiligen Konfiguration bearbeiten. * Bei frei erstellbaren Konfigurationen, beispielsweise einer Konfiguration je Zahlungsart, kann die Einstellung pro Knoten unterschiedlich sein. So lässt sie sich etwa bei „Vorkasse" deaktivieren und bei „Google Pay" aktivieren. Den so gepflegten Wert lesen Sie im Template über [\$wsOptions.get(name, nodeId)](https://dokumentation.websale.de/frontend/referenz/module/ws-options-template-optionen#\$wsoptions-get) aus, wobei `nodeId` die ID des Konfigurationsknotens ist. Konkret: Ist der Schalter im Admin-Interface bei „Vorkasse" aktiviert und bei „Google Pay" nicht, liefert `$wsOptions.get("showPaymentIconInFooter", "payment.payment.bill")` für den Vorkasse-Knoten `true` und für den Google-Pay-Knoten `false` . Das Footer-Icon erscheint also nur bei der Vorkasse. Die Konfigurationsknoten-ID ist **nicht** das Feld `id` innerhalb einer Konfiguration (die „technische ID"). Welche Objekte die korrekte `nodeId` bereitstellen, ist unter [\$wsOptions](/frontend/referenz/module/ws-options-template-optionen) aufgeführt. *** ## Darstellung im Admin-Interface Über `displayOptions.location` legen Sie fest, an welcher Stelle der klickbaren Konfigurationsoberflächen im Admin-Interface die Option erscheint: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ option "paymentInfoText" with {"type": "String", "attachTo": "payment.payment", "displayOptions": {"location": "payment.content"}} }} ``` Dadurch erscheint das Textfeld dieser Option im Admin-Interface direkt im Abschnitt „Inhalt" der jeweiligen Zahlungsart und nicht im allgemeinen Abschnitt „Template Optionen". `location` wirkt **nur in Kombination mit** `attachTo`. Ohne passendes `attachTo` hat die Angabe keinen Effekt. Aktuell erlaubte Werte (die Liste wird erweitert, sobald weitere Oberflächen hinzukommen): | **Konfiguration** | **Location** | **Darstellung** | | ----------------- | ----------------- | ------------------------------------------------------ | | `payment.payment` | `payment.image` | Im Abschnitt „Bild" der Zahlungsarten-Konfiguration. | | `payment.payment` | `payment.content` | Im Abschnitt „Inhalt" der Zahlungsarten-Konfiguration. | Wird `location` nicht angegeben, erscheint die Option in einem allgemeinen Abschnitt „Template Optionen" des jeweiligen Konfigurationsknotens. *** ## Werte auslesen Das Auslesen der gepflegten Optionswerte im Template beschreibt das Modul [\$wsOptions](/frontend/referenz/module/ws-options-template-optionen). Sowohl für globale Optionen als auch für an Konfigurationsknoten gebundene Optionen. # Variablen Source: https://dokumentation.websale.de/frontend/referenz/variablen Eigene und globale Variablen im Template: mit var deklarieren, Werte zuweisen sowie $ws-Module von WEBSALE für Daten und Funktionen nutzen. Variablen dienen zum Speichern von Werten und können für Prüfungen, Berechnungen und Ausgaben im Template genutzt werden. Variablen können Sie selbst definieren, indem Sie `var` davor benutzen und einen eindeutigen Variablenname nach dem obligatorischen `$` festlegen. Daneben gibt es auch die von **WEBSALE** bereitgestellten globalen Variablen ([Module](/frontend/referenz/module)). Diese beginnen immer mit `$ws` und enthalten vorgegebene Funktionen oder Datenfelder. | | | | ---------------------------- | -------------------------------------------------------------------------------- | | `{{ var $myVariable = 10 }}` | Die Variable `$myVariable` wird neu erstellt und in ihr der Wert 10 gespeichert. | | `{{ $myVariable = 42 }}` | In der bereits erstellten Variable `$myVariable` wird der Wert 42 gespeichert. | | `{{= $myVariable }}` | Gib den aktuellen Inhalt von `$myVariable` aus: **42** | Hinweis: `{{= $myVariable }}` gibt den Wert escaped/gefiltert aus (Sonderzeichen/HTML werden “entschärft” und als Text angezeigt). Um den Inhalt ungefiltert auszugeben, muss `{{! $myVariable}}` genutzt werden. Wenn ein Wert einer nicht erstellten Variable zugewiesen wird, erzeugt dies - wie bei allen ungültigen Variablenzugriffen - einen Fehler im Compiler. Das Erstellen einer Variable mit einem bereits verwendeten Namen ist im selben Template nicht erlaubt. # Übersicht - Konfiguration Source: https://dokumentation.websale.de/konfiguration Systemkonfiguration des WEBSALE-Shops: Parameter aller Module wie accounts, basket, general und payment für Verhalten, Funktionen und Backend-Steuerung. In diesem Abschnitt werden alle Parameter-Wert-Paare der Systemkonfiguration beschrieben, die das Verhalten einzelner Module, Komponenten und Funktionen des Onlineshops steuern. Die hier dokumentierten Konfigurationsknoten bilden die technische Grundlage für jeden WEBSALE Shop. Jede Konfiguration besteht aus einem oder mehreren Knoten (z. B. `accounts`, `basket`, `general`), die in einer JSON-ähnlichen Struktur definiert sind. Innerhalb dieser Knoten werden die einzelnen Parameter mit ihren möglichen Werten erläutert.\ So können Administratoren oder Entwickler gezielt nachvollziehen, welche Optionen zur Verfügung stehen und wie diese auf das Verhalten des Systems wirken. Alle Konfigurationseinstellungen können wahlweise über das [Admin Interface](/admin-interface) oder über die [REST API Konfiguration](/schnittstellen) vorgenommen werden. *** ## Alphabetische Übersicht der Konfigurationen * [accounts - Benutzerkonten](/konfiguration/accounts-benutzerkonten) — Der Konfigurationsknoten accounts umfasst alle Einstellungen rund um die Verwaltung von Benutzerkonten im Onlineshop. * [actions - Fehlertexte & E-Mails](/konfiguration/actions-fehlertexte-e-mails) — Der Abschnitt actions beschreibt die Konfiguration von Fehlermeldungen und E-Mail-Vorlagen, die im Zusammenhang mit sogenannten Shopaktionen stehen. * [app - WEBSALE APP](/konfiguration/app-websale-app) — Der Knoten app umfasst alle Konfigurationen für die Anbindung und Steuerung der WEBSALE APP. * [authentication - Authentifizierungs- & Zugriffsdaten](/konfiguration/authentication-authentifizierungs-zugriffsdaten) — Der Konfigurationsbereich authentication dient der Verwaltung von Authentifizierungsinformationen und Zugangsdaten für externe Dienste, Schnittstellen oder Systeme. * [b2b - Business-to-Business (B2B)](/konfiguration/b2b-business-to-business-b2b) — B2B-spezifische Einstellungen (z. B. Gruppen, Berechtigungen, Preislogik). * [basket - Warenkorb](/konfiguration/basket-warenkorb) — Der Abschnitt basket umfasst alle Einstellungen rund um den Warenkorb des Onlineshops. * [creditCheck - Bonitätsprüfung](/konfiguration/creditcheck-bonitatsprufung) * [checkout - Bestellablauf](/konfiguration/checkout-bestellablauf) * [content - Katalog (Kategorien & Produkte)](/konfiguration/content-katalog-kategorien-produkte) — Der Knoten content bildet die zentrale Konfigurationsebene für alle Inhalte des Katalogs. * [customer - Kundendaten](/konfiguration/customer-kundendaten) * [finance - Währungen & Steuern](/konfiguration/finance-wahrungen-steuern) * [general - Allgemeine Shopeinstellungen](/konfiguration/general-allgemeine-shopeinstellungen) — Der Knoten general bündelt sämtliche allgemeinen und systemweiten Grundeinstellungen des Onlineshops. Er ist einer der zentralsten und zugleich umfangreichsten Konfigurationsbereiche und enthält Parameter, die zahlreiche Module, Funktionen und Darstellungen des Shops beeinflussen. * [inquiry - Formulare](/konfiguration/inquiry-formulare) — Der Knoten inquiry steuert shopseitige Formulare (z. B. Kontakt, Widerruf, Retoure, Katalogbestellung). * [maintenance - Wartungsmodus](/konfiguration/maintenance-wartungsmodus) * [messages - Ereignisgesteuerte E-Mails](/konfiguration/messages-ereignisgesteuerte-e-mails) — Der Knoten messages dient zur Konfiguration benutzerdefinierter E-Mail-Benachrichtigungen, die automatisch ausgelöst werden, sobald im Shop bestimmte Ereignisse oder Zustände eintreten. * [newsletter - Newsletter](/konfiguration/newsletter-newsletter) * [payment - Zahlungsmethoden](/konfiguration/payment-zahlungsmethoden) * [search - Sortierung und Filterung](/konfiguration/search-sortierung-und-filterung) * [seoMetaData - Meta-Daten & Seo-Texte](/konfiguration/seometadata-meta-daten-seo-texte) * [security - Sicherheitsregeln](/konfiguration/security-sicherheitsregeln) * [storefrontApi - Storefront-API](/konfiguration/storefrontapi-storefront-api) * [urls - URL (Webadressen)](/konfiguration/urls-url-webadressen) * [Validierungs- und Prüfservices](/konfiguration/validierungs-und-prufservices) * [E-Mails & E-Mail Einstellungen](/konfiguration/e-mails-e-mail-einstellungen) — Das WEBSALE Shopsystem versendet eine Vielzahl von E-Mails zu unterschiedlichen Zwecken, zum Beispiel im Checkout, im Kundenkonto, bei Formularanfragen oder für Benachrichtigungen. *** ## Verwendung von Textbausteinen in Konfigurationen Konfigurationen gelten grundsätzlich plattformweit und stehen damit im Standard allen darin enthaltenen Subshops zur Verfügung. Neben rein technischen Einstellungen können Konfigurationen auch sprachabhängige Inhalte enthalten, die im Frontend angezeigt werden, zum Beispiel Namen, Beschreibungen, Labels oder andere ausgaberelevante Texte. Dies ist insbesondere dann relevant, wenn dieselbe Konfiguration in mehreren Sprachversionen eines Shops verwendet wird. In solchen Fällen ist es nicht ausreichend, einen festen Textwert direkt in der Konfiguration zu hinterlegen, da dieser ansonsten in allen Sprachvarianten identisch ausgegeben würde. **Beispiel:**\ Definition der Länder, die bei der Rechnungs- und Lieferadresse zur Auswahl angeboten werden. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "defaultTaxRate": "finance.taxRates.de", "isoAlpha2": "DE", "isoAlpha3": "DEU", "isoNum": "276", "name": "Deutschland", "usedTaxes": "finance.taxRates.de" } ``` Im obigen Beispiel enthält der Parameter `name` einen festen Textwert. Dieser Wert würde im Frontend direkt angezeigt werden, zum Beispiel in einer Auswahlliste für Länder. In einem mehrsprachigen Shop wäre dies jedoch unflexibel, da dort je nach Sprache statt „Deutschland“ beispielsweise „Germany“ oder „Allemagne“ ausgegeben werden soll. Aus diesem Grund können für solche ausgaberelevanten Texte auch Textbausteine verwendet werden: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "defaultTaxRate": "finance.taxRates.de", "isoAlpha2": "DE", "isoAlpha3": "DEU", "isoNum": "276", "name": "general.country.de.name", "usedTaxes": "finance.taxRates.de" } ``` In diesem Fall verweist der Parameter `name` nicht auf einen festen Text, sondern auf einen Textbaustein. Der eigentliche sprachabhängige Inhalt wird dann über den Textbaustein-Dienst im Admin Interface je Sprache gepflegt. Auf diese Weise kann dieselbe Konfiguration in mehreren Sprachversionen eines Shops verwendet werden, ohne dass die Konfigurationsstruktur selbst je Sprache dupliziert werden muss. Textbausteine in Konfigurationen können grundsätzlich frei vergeben und individuell angelegt werden. Dadurch lassen sich sprachabhängige Frontend-Texte zentral verwalten und konsistent in verschiedenen Konfigurationsbereichen wiederverwenden. Eine Ausnahme bilden automatisch erzeugte Textbausteine für Fehlermeldungen innerhalb von Konfigurationen. Im Bereich `actions` werden für Fehlercodes systemseitig eigene Textbausteine erzeugt, deren Namen mit `ws.error` beginnen. Diese dienen dazu, technische Fehlercodes in verständliche und pflegbare Frontend-Fehlermeldungen zu übersetzen. Weitere Informationen dazu finden sich im Abschnitt [actions - Fehlertexte & E-Mails](/konfiguration/actions-fehlertexte-e-mails). Textbausteine können nicht nur in Konfigurationen, sondern auch in Templates verwendet werden. Dies ist insbesondere sinnvoll, da Templates ebenso wie Konfigurationen grundsätzlich für die gesamte Plattform gelten. Weitere Informationen zur Verwendung von Textbausteinen in Templates finden sich im Abschnitt [Template Engine](/frontend/die-basics/template-engine). *** ## URL-Zugriff auf Konfigurationen (temporär) Die in dieser Dokumentation beschriebenen Konfigurationsknoten entsprechen den technischen Strukturen, auf denen die Einstellungen im Admin Interface basieren. Im Admin Interface sind die einzelnen Knoten thematisch unter den jeweiligen Services (z. B. *Katalog*, *Warenkorb*, *Bestellungen*, *Allgemein*) eingeordnet. Kann ein bestimmter Knoten im Menü nicht gefunden werden, lässt er sich derzeit auch direkt über die URL im Browser aufrufen. Das betrifft insbesondere die Knoten unterhalb von `actions`, also die Fehlertexte und E-Mail-Vorlagen der Shopaktionen. Sie werden in der Konfigurationsübersicht nicht als eigene Gruppe angeboten. Ebenfalls nicht in der Übersicht enthalten ist der Knoten `inquiry.form`, er wird stattdessen über den Service *Anfragen* gepflegt. Die URL folgt dabei stets dem Schema: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https:///admin/config/ ``` Beispiel: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https:///admin/config/content.categoryFieldGroup ``` Dieser Aufruf öffnet direkt die Konfigurationsseite für den Knoten `content.categoryFieldGroup` im Admin Interface. Eine vollständige Liste aller Konfigurationsknoten mit jeweils fertigem Deeplink finden Sie unter [Konfigurations-Deeplinks](/admin-interface/konfigurations-deeplinks) im Bereich Admin Interface. Der Direktaufruf per URL ist derzeit ein **temporärer Workaround**, solange viele Konfigurationen noch über „Konfiguration per Code“ bereitgestellt werden und keine eigene klickbare Oberfläche im Admin Interface besitzen. Sobald die betreffenden Konfigurationen regulär über die Benutzeroberfläche verfügbar sind, behält WEBSALE sich vor, diese Aufruflogik **jederzeit zu deaktivieren**. # actions - Fehlertexte & E-Mails Source: https://dokumentation.websale.de/konfiguration/actions-fehlertexte-e-mails Übersicht des actions-Knotens für Shopaktionen: Konfiguration von Fehlertexten, Fehlercodes und E-Mail-Vorlagen für Login, Merkliste, Konto und mehr. Der Abschnitt `actions` beschreibt die Konfiguration von Fehlermeldungen und E-Mail-Vorlagen. Die Knoten unterhalb von `actions` werden in der Konfigurationsübersicht des Admin-Interface nicht als eigene Gruppe angeboten. Stattdessen wird ein einzelner Knoten über seinen [Deeplink](https://dokumentation.websale.de/admin-interface/konfigurations-deeplinks) oder über die [REST API](https://dokumentation.websale.de/schnittstellen) geöffnet. Für die Fehlertexte selbst ist das zweitrangig, weil diese ausschließlich über Textbausteine gepflegt werden. Der Direktaufruf wird nur für die E-Mail-Vorlagen innerhalb der Aktionen benötigt. *** ## Definition Shopaktionen Als Shopaktionen bezeichnet WEBSALE Anfragen an das Shopsystem, um bestimmte Vorgänge auszuführen – beispielsweise das Hinzufügen eines Produkts zur Merkliste, den Login-Vorgang, das Anlegen eines Benutzerkontos oder andere Aktionen, die eine Interaktion mit dem Backend erfordern. Das Shopsystem prüft dabei die Anfrage und führt die angeforderte Aktion aus, sofern keine Fehler auftreten. Fehler können beispielsweise entstehen, wenn ein Produkt nicht mehr verfügbar ist, erforderliche Voraussetzungen nicht erfüllt sind oder ein unerwarteter Systemfehler vorliegt. In diesen Fällen liefert das System einen Fehlercode zurück. *** ## Fehlermeldungen Solche Fehlercodes sind für die direkte Ausgabe im Frontend jedoch nicht geeignet, da sie für Käufer nicht verständlich sind. Damit im Shop eine sprechende und fachlich passende Fehlermeldung angezeigt werden kann, müssen diese technischen Codes einem lesbaren Text zugeordnet werden. Hierfür erzeugt WEBSALE für jeden Fehlercode automatisch einen Textbaustein. Der im Frontend ausgegebene Fehlertext wird **ausschließlich** über diesen Textbaustein gepflegt. Die Fehlercode-Felder in der Aktions-Konfiguration selbst sind schreibgeschützt. Ihr Wert ist der Name des Textbausteins (beispielsweise `ws.error.accountDelete.actionNotAllowed`), nicht der Fehlertext. Änderungen daran werden im Admin-Interface und über die REST-API beim Speichern abgewiesen. E-Mail-Vorlagen innerhalb der `actions.*`-Konfiguration sind davon nicht betroffen und bleiben regulär editierbar. ### Aufbau der Textbausteine `ws.error` Die Namen dieser Textbausteine beginnen immer mit `ws.error`. Dadurch lassen sie sich auch gezielt über die Suche des Textbaustein-Dienstes im Admin-Interface finden und pflegen. Die Benennung folgt in der Regel diesem Schema: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ws.error.. ``` Dabei entspricht `` in vielen Fällen der betroffenen Aktionskonfiguration unterhalb von `actions`, und `` dem jeweiligen Fehlercode der Aktion. ### Bedeutung eines `ws.error` - Textbausteins ermitteln Beispiel: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ws.error.accountDelete.actionNotAllowed ``` Um die Bedeutung eines solchen Textbausteins zu ermitteln, wird der mittlere Teil des Namens betrachtet, hier also `accountDelete`. Anschließend kann in der Dokumentation nach der zugehörigen Aktionskonfiguration `actions.accountDelete` gesucht werden. Dort findet sich im Abschnitt der Fehlercodes die Beschreibung zu `actionNotAllowed`. Die Beschreibung des Fehlercodes erläutert, in welchem Fall die Meldung ausgegeben wird, und hilft Ihnen somit, den passenden Fehlertext für die Frontend-Darstellung zu formulieren. *** ## Erfolgsmeldungen Erfolgsmeldungen sind nicht Bestandteil der Aktions-Konfigurationen. Sie werden direkt über die Templates der Storefront definiert und können dort bei Bedarf angepasst werden. Die darin enthaltenen Texte lassen sich über die Templates selbst oder über die zugehörigen Textbausteine ändern. *** ## E-Mail-Vorlagen Die Aktionen enthalten zusätzlich Konfigurationsmöglichkeiten für E-Mail-Vorlagen, die im Rahmen bestimmter erfolgreicher Aktionen versendet werden, beispielsweise bei einer erfolgreichen Registrierung oder einer abgeschlossenen Bestellung. Hier können Absender, Empfänger, Betreff und E-Mail-Vorlage hinterlegt werden. Da die Aktionen in der Konfigurationsübersicht nicht angeboten werden, führen zwei Wege zu diesen Feldern: der Deeplink des jeweiligen Knotens oder die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration). Die vollständige Liste aller Aktionsknoten mit fertigem Deeplink steht unter [Konfigurations-Deeplinks](/admin-interface/konfigurations-deeplinks). *** ## REST API Konfiguration Fehlercode-Felder, für die ein `ws.error`-Textbaustein erzeugt worden ist, sind in der Aktions-Konfiguration schreibgeschützt hinterlegt. Sie können daher nicht über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) bearbeitet werden - die Anpassung des ausgegebenen Textes erfolgt ausschließlich über den jeweiligen Textbaustein. E-Mail-Vorlagen sind davon nicht betroffen. *** ## Übersicht der actions für Fehlertexte & E-Mails * [actions - Alphabetische Übersicht](/konfiguration/actions-fehlertexte-e-mails/actions-alphabetische-ubersicht) — Über diese Seiten lassen sich alle Aktionen schnell auffinden und direkt zur entsprechenden thematischen Gruppe aufrufen. Sie dient damit als zentrale Referenz für eine gezielte Suche und eine effiziente Bearbeitung einzelner Aktionskonfigurationen. * [actions - Anmeldung & Registrierung](/konfiguration/actions-fehlertexte-e-mails/actions-anmeldung-registrierung) — Diese Seite enthält alle Aktionen, die den Anmeldungs- und Registrierungsprozess im Onlineshop betreffen. Hier sind alle Meldungen und E-Mail-Vorlagen dokumentiert, die beim Anmelden, beim Entsperren eines Kontos oder beim Zurücksetzen eines Passworts ausgegeben werden. * [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) — Diese Seite enthält alle Aktionen, die das Benutzerkonto betreffen, und enthält somit alle Meldungen und E-Mail-Vorlagen, die beim Erstellen, Ändern, Löschen und Prüfen von Kontodaten auftreten. * [actions - Formulare](/konfiguration/actions-fehlertexte-e-mails/actions-formulare) — Diese Seite enthält alle Aktionen, die das Absenden von Formularen betreffen. Hier werden die zugehörigen Meldungen und E-Mail-Vorlagen dokumentiert, die beim Versenden von Formularen über den Shop ausgegeben werden – beispielsweise bei Kontakt-, Anfrage- oder Serviceformularen. * [actions - Newsletter](/konfiguration/actions-fehlertexte-e-mails/actions-newsletter) — Diese Seite enthält alle Aktionen, die den Newsletter-Versand betreffen. * [actions - Produkte](/konfiguration/actions-fehlertexte-e-mails/actions-produkte) — Diese Seite enthält alle Aktionen, die im Zusammenhang mit Produkten stehen. * [actions - Sicherheit & Datenschutz](/konfiguration/actions-fehlertexte-e-mails/actions-sicherheit-datenschutz) — Diese Seite enthält alle Aktionen, die die Sicherheit und den Datenschutz im Shop betreffen. Dazu zählen Meldungen und Benachrichtigungen rund um die Sitzungssteuerung und den Consent Layer zur Verwaltung von Einwilligungen. * [actions - Testmodus](/konfiguration/actions-fehlertexte-e-mails/actions-testmodus) — Dieser Bereich umfasst alle Aktionen, die zur Steuerung des Testmodus dienen. Sie ermöglichen das Aktivieren, Deaktivieren oder Umschalten des Testmodus innerhalb des Systems. * [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) — Diese Seite enthält alle Aktionen, die während des Bestellvorgangs im Shop ausgeführt werden. # actions - Alphabetische Übersicht Source: https://dokumentation.websale.de/konfiguration/actions-fehlertexte-e-mails/actions-alphabetische-ubersicht Alphabetische Übersicht aller WEBSALE-Shopaktionen mit Direktlink zur jeweiligen thematischen Gruppe – als zentrale Referenz für gezielte Action-Suche. Über diese Seite lassen sich alle Aktionen schnell auffinden und direkt zur entsprechenden thematischen Gruppe aufrufen. Sie dient damit als zentrale Referenz für eine gezielte Suche und eine effiziente Bearbeitung einzelner Aktionskonfigurationen. ## Alphabetische Übersicht der Aktionen | **Aktion** | **Beschreibung & Gruppierung** | | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | `acceptInvitation` | [actions - Anmeldung & Registrierung](/konfiguration/actions-fehlertexte-e-mails/actions-anmeldung-registrierung) | | `accountActivate` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `accountActivateOptIn` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `accountDelete` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `accountDisplayNameUpdate` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `accountRegister` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `addressCreate` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `addressDelete` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `addressUpdate` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `backInStockActivate` | [actions - Produkte](/konfiguration/actions-fehlertexte-e-mails/actions-produkte) | | `backInStockDeactivate` | [actions - Produkte](/konfiguration/actions-fehlertexte-e-mails/actions-produkte) | | `basketItemAdd` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `basketItemDelete` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `basketItemUpdate` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `blacklistAdd` | [actions - Newsletter](/konfiguration/actions-fehlertexte-e-mails/actions-newsletter) | | `checkoutAccountTypeSelect` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `checkoutBillAddressSelect` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `checkoutConfirm` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `checkoutPaymentUpdate` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `checkoutPseudoCCSelect` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `checkoutSetFreeFields` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `checkoutSetGuestEmail` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `checkoutShippingAddressSelect` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `checkoutShippingMethodUpdate` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `checkoutUseDifferentShippingAddress` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `checkPasswordStrength` | [actions - Anmeldung & Registrierung](/konfiguration/actions-fehlertexte-e-mails/actions-anmeldung-registrierung) | | `confirmZipCode` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `consentChange` | [actions - Sicherheit & Datenschutz](/konfiguration/actions-fehlertexte-e-mails/actions-sicherheit-datenschutz) | | `creditCardDelete` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `directOrder` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `emailUpdate` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `emailVerify` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `guestRegister` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `inquiryCheck` | [actions - Formulare](/konfiguration/actions-fehlertexte-e-mails/actions-formulare) | | `inquirySend` | [actions - Formulare](/konfiguration/actions-fehlertexte-e-mails/actions-formulare) | | `inventoryReserve` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `login` | [actions - Anmeldung & Registrierung](/konfiguration/actions-fehlertexte-e-mails/actions-anmeldung-registrierung) | | `newsletterSubscribe` | [actions - Newsletter](/konfiguration/actions-fehlertexte-e-mails/actions-newsletter) | | `newsletterUnsubscribe` | [actions - Newsletter](/konfiguration/actions-fehlertexte-e-mails/actions-newsletter) | | `paymentVaultCreate` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `paymentVaultRemove` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `paymentVaultSetup` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `passwordForgotten` | [actions - Anmeldung & Registrierung](/konfiguration/actions-fehlertexte-e-mails/actions-anmeldung-registrierung) | | `productRatingAdd` | [actions - Produkte](/konfiguration/actions-fehlertexte-e-mails/actions-produkte) | | `productRatingDelete` | [actions - Produkte](/konfiguration/actions-fehlertexte-e-mails/actions-produkte) | | `productRatingUpdate` | [actions - Produkte](/konfiguration/actions-fehlertexte-e-mails/actions-produkte) | | `resetPassword` | [actions - Anmeldung & Registrierung](/konfiguration/actions-fehlertexte-e-mails/actions-anmeldung-registrierung) | | `sessionUnlock` | [actions - Sicherheit & Datenschutz](/konfiguration/actions-fehlertexte-e-mails/actions-sicherheit-datenschutz) | | `sessionUpdate` | [actions - Sicherheit & Datenschutz](/konfiguration/actions-fehlertexte-e-mails/actions-sicherheit-datenschutz) | | `setCustomerData` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `setMainAddress` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `subAccountCreate` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `testModeChange` | [actions - Testmodus](/konfiguration/actions-fehlertexte-e-mails/actions-testmodus) | | `testModeOff` | [actions - Testmodus](/konfiguration/actions-fehlertexte-e-mails/actions-testmodus) | | `testModeOn` | [actions - Testmodus](/konfiguration/actions-fehlertexte-e-mails/actions-testmodus) | | `unlockLogin` | [actions - Anmeldung & Registrierung](/konfiguration/actions-fehlertexte-e-mails/actions-anmeldung-registrierung) | | `userInvitation` | [actions - Benutzerkonto](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto) | | `voucherAdd` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `voucherDelete` | [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) | | `watchListAdd` | [actions - Produkte](/konfiguration/actions-fehlertexte-e-mails/actions-produkte) | | `watchListDelete` | [actions - Produkte](/konfiguration/actions-fehlertexte-e-mails/actions-produkte) | | `watchListItemAdd` | [actions - Produkte](/konfiguration/actions-fehlertexte-e-mails/actions-produkte) | | `watchListItemDelete` | [actions - Produkte](/konfiguration/actions-fehlertexte-e-mails/actions-produkte) | # actions - Anmeldung & Registrierung Source: https://dokumentation.websale.de/konfiguration/actions-fehlertexte-e-mails/actions-anmeldung-registrierung Aktionen rund um Anmeldung und Registrierung im Shop: Fehlertexte und E-Mail-Vorlagen für Login, Kontoentsperrung sowie Passwort-Zurücksetzen. Diese Seite enthält alle Aktionen, die den Anmeldungs- und Registrierungsprozess im Onlineshop betreffen. Hier sind alle Meldungen und E-Mail-Vorlagen dokumentiert, die beim Anmelden, Entsperren eines Kontos oder beim Zurücksetzen eines Passworts ausgegeben etc. werden. *** ## Übersicht der Aktionen Die hier aufgeführten Aktionen wurden **thematisch gruppiert**, um die zugehörigen Fehlermeldungen und E-Mail-Vorlagen übersichtlich darzustellen. Aktionen, die inhaltlich zu einem anderen Themenbereich gehören, finden sich in den entsprechenden Abschnitten dieser Dokumentation oder in der [alphabetischen Übersicht der Aktionen](/konfiguration/actions-fehlertexte-e-mails/actions-alphabetische-ubersicht). #### Auszug der Grundstruktur `actions` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "actions": { "acceptInvitation": {...}, "checkPasswordStrength": {...}, "login": {...}, "unlockLogin": {...}, "passwordForgotten": {...}, "resetPassword": {...} } } ``` #### Aktionsübersicht | **Aktion** | **Beschreibung** | | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `acceptInvitation` | Definiert die Fehlermeldungen, die beim Annehmen einer Einladung zu einem B2B-Konto ausgegeben werden. | | `checkPasswordStrength` | Steuert, ob der Shop die Stärke eines Passworts prüft. | | `login` | Definiert die Fehlermeldungen, die beim Anmeldevorgang im Kundenkonto ausgegeben werden. | | `unlockLogin` | Definiert die Fehlermeldungen, die beim Aufheben einer Login-Sperre ausgegeben werden. | | `passwordForgotten` | Definiert die Fehlermeldungen, die beim “Passwort vergessen”-Vorgang ausgegeben werden, sowie die E-Mail, die versendet wird. | | `resetPassword` | Definiert die Fehlermeldungen, die beim Ändern des Passworts ausgegeben werden. | *** ## `actions.acceptInvitation` - Einladung annehmen (B2B) Mithilfe der Aktion `acceptInvitation` werden die Fehlermeldungen gesteuert, die ausgegeben werden, wenn ein eingeladener Nutzer eine B2B-Kontoeinladung über einen Double-Opt-In-Link annimmt. #### **Beispielkonfiguration** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "invalidAccountId": "", "actionNotAllowed": "" } } ``` #### Parameterübersicht | Parameter | Typ | Beschreibung | | ------------------ | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `invalidAccountId` | string | Fehlermeldung, die ausgegeben wird, wenn der Double-Opt-In-Token keinem Kundenkonto zugeordnet werden kann.

    | | `actionNotAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn der Double-Opt-In-Token ungültig ist.

    | *** ## `actions.checkPasswordStrength` - Passwortstärke resp. Passwortsicherheit Mit der Aktion `checkPasswordStrength` wird gesteuert, ob das Shopsystem bei Aktionen wie Registrierung oder Passwortänderung die Stärke eines Passworts serverseitig prüft (z. B. Mindestlänge, Komplexität). #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------------------------------------------------------------------------- | | `active` | bool | Aktiviert bzw. deaktiviert die serverseitige Prüfung der Passwortstärke.
    Default: `true` | *** ## `actions.login` - Anmeldung Mithilfe der Aktion `login` wird definiert, welche Fehlermeldungen beim Anmeldevorgang im Kundenkonto ausgegeben werden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingId": "", "missingPassword": "", "emailCheckFailed": "", "loginBlocked": "", "invalidCredentials": "", "ipAddressBlocked": "", "duplicatePendingReview": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | array | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Login-ID (z.B. E-Mail-Adresse) übermittelt wurde.

    | | `missingPassword` | string | Fehlermeldung, die ausgegeben wird, wenn kein Passwort übermittelt wurde.

    | | `emailCheckFailed` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene E-Mail-Adresse als ungültig bewertet wird.

    | | `loginBlocked` | string | Fehlermeldung, die ausgegeben wird, wenn das Benutzerkonto vorübergehend gesperrt ist.

    | | `invalidCredentials` | string | Fehlermeldung, die ausgegeben wird, wenn die Kombination aus E-Mail-Adresse und Passwort nicht stimmt.

    | | `ipAddressBlocked` | string | Fehlermeldung, die ausgegeben wird, wenn die aktuelle IP-Adresse blockiert ist (Blacklist).

    | | `duplicatePendingReview` | string | Fehlermeldung, die ausgegeben wird, wenn eine Anmeldung nicht möglich ist, weil sich das Konto noch in der Duplettenprüfung befindet (siehe [accounts.account](/konfiguration/accounts-benutzerkonten) → `duplicate`).

    | *** ## `actions.unlockLogin` - Anmeldung entsperren Mit der Aktion `unlockLogin` können Fehlermeldungen definiert werden, die beim Aufheben einer Login-Sperre für ein Kundenkonto ausgegeben werden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "unauthorized": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `unauthorized` | string | Fehlermeldung, die ausgegeben wird, wenn die Entsperrung nicht zulässig ist (z.B. ungültiger Link oder fehlende Berechtigung).

    | *** ## `actions.passwordForgotten` - Passwort vergessen Mit der Aktion `passwordForgotten` werden die Fehlermeldungen definiert, die beim Vorgang „Passwort vergessen“ angezeigt werden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": { "template": "password_forgotten.htm", "subject": "Passwort zurücksetzen", "fromAddress": "noreply@meinshop.de", "fromName": "Mein Onlineshop" }, "errorCodes": { "missingEmail": "", "emailCheckFailed": "", "passwordRecoveryFailed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `email` | object | Konfiguriert die E-Mail, die beim Zurücksetzen des Passworts versendet wird. Betreff, Absender und Template werden über die allgemeinen E-Mail-Parameter gesteuert, siehe hier: [E-Mail Einstellungen](/konfiguration/e-mails-e-mail-einstellungen) | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingEmail` | string | Fehlermeldung, die ausgegeben wird, wenn keine E-Mail-Adresse übermittelt wurde.

    | | `emailCheckFailed` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene E-Mail-Adresse als ungültig bewertet wurde.

    | | `passwordRecoveryFailed` | string | Fehlermeldung, die ausgegeben wird, wenn der Passwort-Reset fehlschlägt.

    | *** ## `actions.resetPassword` - Passwort zurücksetzen Mithilfe der Aktion `resetPassword` wird festgelegt, welche Fehlermeldungen beim Ändern des Passworts für ein bestehendes Kundenkonto ausgegeben werden und welche Prüfungen/Aktionen ausgeführt werden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "autoLogout": true, "checkOldPassword": true, "checkLoginID": false, "errorCodes": { "notLoggedIn": "", "missingEmail": "", "emailMismatch": "", "missingPassword": "", "passwordMismatch": "", "missingPasswordAuth": "", "failedPasswordAuth": "", "passwordCheckFailed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | `autoLogout` | bool | Legt fest, ob der Kunde nach einer erfolgreichen Passwortänderung automatisch ausgeloggt wird.
    Default: `true` | | `checkOldPassword` | bool | Gibt an, ob zur Änderung des Passworts zusätzlich das bisherige Passwort abgefragt und geprüft werden soll.
    Default: `true` | | `checkLoginID` | bool | Wenn `true`, wird zusätzlich geprüft, ob die angegebene Login-ID/E-Mail mit dem Konto übereinstimmt.
    Default: `false` | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `notLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn der Benutzer nicht eingeloggt ist.

    | | `missingEmail` | string | Fehlermeldung, die ausgegeben wird, wenn keine E-Mail-Adresse übermittelt wurde.

    | | `emailMismatch` | string | Fehlermeldung, die ausgegeben wird, wenn die alte E-Mail-Adresse nicht korrekt übergeben wurde.

    | | `missingPassword` | string | Fehlermeldung, die ausgegeben wird, wenn kein Passwort übermittelt wurde.

    | | `passwordMismatch` | string | Fehlermeldung, die ausgegeben wird, wenn Passwort und Passwort-Bestätigung nicht übereinstimmen.

    | | `missingPasswordAuth` | string | Fehlermeldung, die ausgegeben wird, wenn das aktuelle Passwort als Bestätigung erforderlich, aber nicht angegeben ist.

    | | `failedPasswordAuth` | string | Fehlermeldung, die ausgegeben wird, wenn das eingegebene, aktuelle Passwort, nicht korrekt ist.

    | | `passwordCheckFailed` | string | Fehlermeldung, die ausgegeben wird, wenn das Passwort die Mindestanforderungen nicht erfüllt.

    | # actions - Benutzerkonto Source: https://dokumentation.websale.de/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto Shopaktionen zum Benutzerkonto: Meldungen und E-Mail-Vorlagen für das Erstellen, Ändern, Löschen und Prüfen von Kontodaten im WEBSALE Onlineshop. Diese Seite enthält alle Aktionen, die das Benutzerkonto betreffen und enthält somit alle Meldungen und E-Mail-Vorlagen, die beim Erstellen, Ändern, Löschen und Prüfen von Kontodaten auftreten. ## Übersicht der Aktionen Folgend eine Auflistung aller Aktionen, die für Benutzerkonten angeboten werden. Aktionen, die inhaltlich zu einem anderen Themenbereich gehören, finden sich in den entsprechenden Abschnitten dieser Dokumentation oder in der [alphabetischen Übersicht der Aktionen](/konfiguration/actions-fehlertexte-e-mails/actions-alphabetische-ubersicht). #### Auszug der Grundstruktur `actions` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "actions": { ... "accountActivate": {...}, "accountActivateOptIn": {...}, "accountDelete": {...}, "accountDisplayNameUpdate": {...}, "accountRegister": {...}, "addressCreate": {...}, "addressDelete": {...}, "addressUpdate": {...}, "creditCardDelete": {...}, "confirmZipCode": {...}, "emailUpdate": {...}, "emailVerify": {...}, "paymentVaultCreate": {...}, "paymentVaultRemove": {...}, "paymentVaultSetup": {...}, "setCustomerData": {...}, "setMainAddress": {...}, "subAccountCreate": {...}, "userInvitation": {...}, ... } } ``` #### Aktionsübersicht | **Aktion** | **Beschreibung** | | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `accountActivate` | Konfiguriert die Opt-In-E-Mail sowie die Fehlermeldungen bei der Aktivierung eines bestehenden Kundenkontos durch Bestandskunden. | | `accountActivateOptIn` | Konfiguriert die Verifizierungs-E-Mail sowie die Fehlermeldungen bei der Bestätigung des Opt-In-Links im Rahmen der Bestandskundenaktivierung. | | `accountDelete` | Konfiguriert die verwendeten E-Mail-Vorlagen für Bestätigungs- und Double-Opt-In-Mails sowie mögliche Fehlermeldungen bei der Kontolöschung. | | `accountDisplayNameUpdate` | Hier wird festgelegt, welche Fehlertexte bei fehlenden Eingaben oder nicht angemeldeten Benutzern während der Änderung des Namens ausgegeben werden. | | `accountRegister` | Definiert die Fehlertexte bei der Registrierung neuer Kundinnen und Kunden. | | `addressCreate` | Definiert die Fehlermeldungen beim Erstellen neuer Adressen im Kundenkonto. | | `addressUpdate` | Definiert die Fehlermeldungen beim Aktualisieren bestehender Adressen im Kundenkonto. | | `addressDelete` | Definiert die Fehlermeldungen beim Löschen der Adressen im Kundenkonto. | | `creditCardDelete` | Definiert die Fehlermeldungen beim Entfernen gespeicherter Pseudokreditkartendaten aus dem Kundenkonto. | | `confirmZipCode` | Definiert die Fehlermeldungen bei der Überprüfung einer evtl. ungültig angegebenen Postleitzahl. | | `emailUpdate` | Definiert die Fehlermeldungen bei der Aktualisierung der E-Mail-Adresse im Kundenkonto. | | `emailVerify` | Definiert die Fehlermeldungen bei der Verifizierung der E-Mail-Adresse im Kundenkonto. | | `paymentVaultSetup` | Definiert Fehlermeldungen bei der Vorbereitung einer Verknüpfung des Kundenkontos mit dem Konto beim Zahlungsanbieter. | | `paymentVaultCreate` | Definiert Fehlermeldungen beim Erstellen der Verknüpfung des Kundenkontos mit dem Konto beim Zahlungsanbieter. | | `paymentVaultRemove` | Definiert Fehlermeldungen beim Aufheben einer bestehenden Verknüpfung mit dem Konto des Zahlungsanbieters. | | `setCustomerData` | Definiert die Fehlermeldungen beim Speichern oder Aktualisieren von Kundendaten im Shop. | | `setMainAddress` | Definiert die Fehlermeldungen beim festlegen einer Hauptadresse im Kundenkonto. | | `subAccountCreate` | Definiert die Fehlermeldungen beim Erstellen neuer Unterkonten innerhalb eines bestehenden Kundenkontos. | | `userInvitation` | Definiert die Fehlermeldungen beim Einladen neuer Benutzerinnen und Benutzer, beispielsweise zu Unterkonten oder gemeinsam genutzten Kundenkonten.
    Hier werden sowohl die Einladungs-Mail als auch mögliche Fehlermeldungen bei der Einladungskontrolle definiert. | ## `actions.account*` - Benutzer Die unter diesem Abschnitt beschriebenen Aktionen betreffen Vorgänge rund um das Benutzerkonto. Sie werden immer dann ausgelöst, wenn der Benutzer eine entsprechende Aktion im Shop ausführt - beispielsweise bei der Registrierung, bei Änderungen am Profil oder beim Löschen des Kontos. ### `actions.accountDelete` - Kontolöschung Mithilfe der Aktion `accountDelete` werden die Fehlermeldungen für Anfragen zur Löschung eines Kundenkontos gesteuert. Gleichzeitig wird hier konfiguriert, welche Bestätigungs-E-Mail nach erfolgreicher Löschung versendet wird und ob zusätzlich eine Double-Opt-In-E-Mail zur Bestätigung des Löschwunsches eingesetzt wird. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "confirmationEmail": { "fromAddress": "noreply@websale.de", "fromName": "Mein Onlineshop", "subject": "Mein Onlineshop | Löschung ihres Kontos", "template": "accountDelete.htm" }, "doubleOptInEmail": { "enabled": false, "fromAddress": "noreply@websale.de", "fromName": "Mein Onlineshop", "subject": "Mein Onlineshop | Löschung ihres Kontos", "template": "accountDeleteOptIn.htm" }, "errorCodes": { "actionNotAllowed": "", "notLoggedIn": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `confirmationEmail` | object | Konfiguriert die Bestätigungs-E-Mail, die nach erfolgter Kontolöschung an den Kunden gesendet wird.
    Der Versand kann über `enabled` aktiviert oder deaktiviert werden. Betreff, Absender und Template werden über die allgemeinen E-Mail-Parameter gesteuert, siehe hier: [E-Mails & E-Mail Einstellungen](/konfiguration/e-mails-e-mail-einstellungen) | | `doubleOptInEmail` | object | Konfiguriert die optionale Double-Opt-In-Email, mit der der Kunde seine Kontolöschung vor der Ausführung bestätigen muss.
    Der Versand kann über `enabled` aktiviert oder deaktiviert werden. Betreff, Absender und Template werden über die allgemeinen E-Mail-Parameter gesteuert, siehe hier: [E-Mails & E-Mail Einstellungen](/konfiguration/e-mails-e-mail-einstellungen) | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `notLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn der Benutzer nicht eingeloggt ist.

    | | `actionNotAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn die Aktion nicht erlaubt ist.

    | ### `actions.accountDisplayNameUpdate` - Anzeigename ändern Mithilfe der Aktion `accountDisplayNameUpdate` werden die Fehlermeldungen bei der Aktualisierung des öffentlichen Anzeigenamens gesteuert. Dieser wird ausschließlich bei abgegebenen Kundenbewertungen angezeigt und ersetzt dort den echten Namen. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingDisplayName": "", "notLoggedIn": "", "insufficientPrivileges": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingDisplayName` | string | Fehlermeldung, die ausgegeben wird, wenn der Anzeigename nicht übergeben wurde.

    | | `notLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn der Benutzer nicht eingeloggt ist.

    | | `insufficientPrivileges` | string | Fehlermeldung, die ausgegeben wird, wenn ein Mitarbeiterkonto (Sub-Account) nicht über die nötige Berechtigung verfügt, den eigenen Anzeigenamen zu ändern.

    | ### `actions.accountRegister` - Benutzer registrieren Die Aktion `accountRegister` steuert die Fehlermeldungen bei der Registrierung eines neuen Benutzerkontos im Shop. Optional kann nach erfolgreicher Registrierung eine Bestätigungs- bzw. Verifizierungsmail über `verifyEmail` versendet werden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "accountAlreadyExists": "", "duplicateAccountFound": "", "emailCheckFailed": "", "missingEmail": "", "missingId": "", "missingPassword": "", "passwordCheckFailed": "", "passwordMismatch": "" }, "verifyEmail": { "fromAddress": "noreply@websale.de", "fromName": "Mein Onlineshop", "subject": "Mein Onlineshop | Registrierung", "template": "accountRegister.htm" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ----------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `accountAlreadyExists` | string | Fehlermeldung, die ausgegeben wird, wenn der Account bereits existiert.

    | | `duplicateAccountFound` | string | Fehlermeldung, die ausgegeben wird, wenn bei der Registrierung eine Dublette gefunden wurde (Duplettenprüfung über [accounts.account](/konfiguration/accounts-benutzerkonten) → `duplicate`).

    | | `emailCheckFailed` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene E-Mail-Adresse als ungültig bewertet wurde.

    | | `missingEmail` | string | Fehlermeldung, die ausgegeben wird, wenn keine E-Mail-Adresse übermittelt wurde.

    | | `missingId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Login-ID übermittelt wurde.

    | | `missingPassword` | string | Fehlermeldung, die ausgegeben wird, wenn kein Passwort übermittelt wurde.

    | | `passwordCheckFailed` | string | Fehlermeldung, die ausgegeben wird, wenn das Passwort die Mindestanforderungen nicht erfüllt.

    | | `passwordMismatch` | string | Fehlermeldung, die ausgegeben wird, wenn Passwort und Passwort-Bestätigung nicht übereinstimmen.

    | | `verifyEmail` | object | Konfiguriert die E-Mail, über die der Kunde seine Registrierung bestätigen kann.
    Betreff, Absender und Template werden über die allgemeinen E-Mail-Parameter gesteuert, siehe hier: [E-Mails & E-Mail Einstellungen](/konfiguration/e-mails-e-mail-einstellungen) | ### `actions.accountActivate` - Bestandskunden aktivieren Die Aktion `accountActivate` steuert die Opt-In-E-Mail sowie die Fehlermeldungen bei der Aktivierung eines bereits im Shop vorhandenen Kundenkontos durch Bestandskunden. Voraussetzung ist, dass der Kundendatensatz zuvor im Shop angelegt wurde (beispielsweise über einen Import). Weitere Informationen zur Konfiguration der Bestandskundenregistrierung finden sich unter [accounts.account](/konfiguration/accounts-benutzerkonten). **Beispielkonfiguration** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "optInEmail": { "template": "account/activateAccountOptIn.htm", "subject": "Registration attempt for your Account", "fromAddress": "no-reply@websale.de", "fromName": "Websale Shop" }, "errorCodes": { "disabled": "", "missingId": "", "missingCustomerNumber": "", "missingPassword": "", "passwordMismatch": "", "emailCheckFailed": "", "passwordCheckFailed": "", "accountNotFound": "", "accountAlreadyActivated": "" } } ``` **Parameterübersicht** | **Parameter** | **Typ** | **Beschreibung** | | ------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `optInEmail` | object | Konfiguriert die Opt-In-E-Mail, die nach der Aktivierung an die im Kundenkonto hinterlegte Adresse versendet wird.
    Der Kunde muss die Registrierung darüber nochmals bestätigen.
    Der Versand kann in [accounts.account](/konfiguration/accounts-benutzerkonten) über `requireOptIn` deaktiviert werden. Betreff, Absender und Template werden über die allgemeinen E-Mail-Parameter gesteuert. | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `disabled` | string | Fehlermeldung, die ausgegeben wird, wenn die Bestandskundenregistrierung deaktiviert ist.

    | | `missingId` | string | Fehlermeldung, die ausgegeben wird, wenn keine E-Mail-Adresse übermittelt wurde.

    | | `missingCustomerNumber` | string | Fehlermeldung, die ausgegeben wird, wenn keine Kundennummer übermittelt wurde.

    | | `missingPassword` | string | Fehlermeldung, die ausgegeben wird, wenn kein Passwort übermittelt wurde.

    | | `passwordMismatch` | string | Fehlermeldung, die ausgegeben wird, wenn Passwort und Passwort-Bestätigung nicht übereinstimmen.

    | | `emailCheckFailed` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene E-Mail-Adresse als ungültig bewertet wurde.

    | | `passwordCheckFailed` | string | Fehlermeldung, die ausgegeben wird, wenn das Passwort die Mindestanforderungen nicht erfüllt.

    | | `accountNotFound` | string | Fehlermeldung, die ausgegeben wird, wenn kein Konto mit den übermittelten Daten gefunden werden konnte.

    | | `accountAlreadyActivated` | string | Fehlermeldung, die ausgegeben wird, wenn das Konto bereits aktiviert wurde.

    | ### `actions.accountActivateOptIn` - Bestandskundenaktivierung Opt-In Bestätigung Die Aktion `accountActivateOptIn` steuert die Verifizierungs-E-Mail sowie die Fehlermeldungen, die bei der Bestätigung des Opt-In-Links im Rahmen der Bestandskundenaktivierung auftreten. Diese Aktion greift, nachdem der Kunde den Opt-In-Link aus der von `accountActivate` versendeten E-Mail aufgerufen hat. **Beispielkonfiguration** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "verifyEmail": { "template": "account/email_verify.htm", "subject": "Verify your Email-Address", "fromAddress": "no-reply@websale.de", "fromName": "Websale Shop" }, "errorCodes": { "actionNotAllowed": "", "accountAlreadyExists": "" } } ``` **Parameterübersicht** | **Parameter** | **Typ** | **Beschreibung** | | ---------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `verifyEmail` | object | Konfiguriert die Verifizierungs-E-Mail, die nach erfolgreicher Bestätigung des Opt-In-Links an den Kunden versendet wird. Betreff, Absender und Template werden über die allgemeinen E-Mail-Parameter gesteuert. | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `actionNotAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn das Opt-In-Token ungültig oder abgelaufen ist.

    | | `accountAlreadyExists` | string | Fehlermeldung, die ausgegeben wird, wenn eine Aufteilung in Firmen-/Mitarbeiterkonten konfiguriert ist und das Mitarbeiterkonto nicht angelegt werden konnte, weil die E-Mail-Adresse bereits vergeben ist.

    | ## `actions.address*` - Adressdaten Dieser Abschnitt enthält alle Aktionen, die die Verwaltung von Adressdaten im Benutzerkonto betreffen. Hier werden die Meldungen dokumentiert, die beim Anlegen, Ändern oder Löschen von Rechnungs- und Lieferadressen im Shop ausgegeben werden. ### `actions.addressCreate` - Adresse anlegen Die Aktion `addressCreate` steuert die Fehlermeldungen beim Anlegen einer neuen Adresse im Kundenkonto. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "notLoggedIn": "", "emptyAddress": "", "unknownField": "", "invalidFieldType": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `notLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn der Benutzer nicht eingeloggt ist.

    | | `emptyAddress` | string | Fehlermeldung, die ausgegeben wird, wenn keine oder unvollständige Adressdaten übermittelt wurden.

    | | `unknownField` | string | Fehlermeldung, die ausgegeben wird, wenn Felder übergeben wurden, die dem System nicht bekannt sind.

    | | `invalidFieldType` | string | Fehlermeldung, die ausgegeben wird, wenn Felder mit einem ungültigen Dateityp gefüllt sind.

    | ### `actions.addressDelete` - Adresse löschen Die Aktion `addressDelete` steuert die Fehlermeldungen beim Löschen einer bestehenden Adresse im Kundenkonto. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "notLoggedIn": "", "invalidAddressId": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `notLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn der Benutzer nicht eingeloggt ist.

    | | `invalidAddressId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Adress-ID ungültig ist oder die Adresse nicht gefunden werden kann.

    | ### `actions.addressUpdate` - Adresse bearbeiten Die Aktion `addressUpdate` steuert die Fehlermeldungen, die beim Bearbeiten einer bestehenden Adresse im Kundenkonto auftreten. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "emptyAddress": "", "invalidAddressId": "", "unknownField": "", "invalidFieldType": "", "expressCheckoutNotAllowed": "", "readOnlyField": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `emptyAddress` | string | Fehlermeldung, die ausgegeben wird, wenn keine oder unvollständige Adressdaten übermittelt wurden.

    | | `invalidAddressId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Adress-ID ungültig ist oder die Adresse nicht gefunden werden kann.

    | | `unknownField` | string | Fehlermeldung, die ausgegeben wird, wenn Felder übergeben wurden, die dem System nicht bekannt sind.

    | | `invalidFieldType` | string | Fehlermeldung, die ausgegeben wird, wenn Felder mit einem ungültigen Dateityp gefüllt sind.

    | | `expressCheckoutNotAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn die Adresse im Rahmen eines Express-Checkouts nicht geändert werden darf.

    | | `readOnlyField` | string | Fehlermeldung, die ausgegeben wird, wenn versucht wird, ein schreibgeschütztes Feld zu ändern.

    | ## `actions.creditCardDelete` - Gespeicherte Kreditkarte löschen Die Aktion `creditCardDelete` definiert die Fehlermeldungen, die beim Löschen einer gespeicherten Kreditkarte ausgegeben werden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "notLoggedIn": "", "missingPseudoId": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ----------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `notLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn der Benutzer nicht eingeloggt ist.

    | | `missingPseudoId` | string | Fehlermeldung, die ausgegeben wird, wenn keine oder eine ungültige Karten-Referenz übermittelt wurde bzw. die Karte nicht gefunden werden kann.

    | ## `actions.confirmZipCode` - Postleitzahl bestätigen Die Aktion `confirmZipCode` definiert die Fehlermeldungen für die Prüfung, ob die übermittelte Postleitzahl zu einer angegebenen Bestellung passt. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingZipCode": "", "missingOrderId": "", "invalidZipCode": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------- | ------- | ------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingZipCode` | string | Fehlermeldung, die ausgegeben wird, wenn keine Postleitzahl übermittelt wurde.

    | | `missingOrderId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Bestellnummer übermittelt wurde.

    | | `invalidZipCode` | string | Fehlermeldung, die ausgegeben wird, wenn die Postleitzahl nicht zur Bestellung passt.

    | ## `actions.email*` - E-Mail-Adresse für den Login In diesem Abschnitt werden alle Aktionen rund um die E-Mail-Adresse für den Login behandelt. Hier können die E-Mails und Fehlermeldungen konfiguriert werden, die beim Ändern der Login-E-Mail-Adresse sowie bei der Bestätigung bzw. Verifizierung der E-Mail-Adresse über Bestätigungslinks zum Einsatz kommen. ### `actions.emailUpdate` - E-Mail-Adresse ändern Mit der Aktion `emailUpdate` werden E-Mails und Fehlermeldungen bei der Änderung der E-Mail-Adresse eines bestehenden Kundenkontos definiert. Dabei können zwei E-Mail-Typen genutzt werden: eine optionale Double-Opt-In-E-Mail und eine Bestätigungs-/Verifizierungs-E-Mail an die neue Adresse. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "verifyEmail": { "template": "email_update_verify.htm", "subject": "Bitte bestätigen Sie Ihre neue E-Mail-Adresse", "fromAddress": "noreply@meinshop.de", "fromName": "Mein Onlineshop" }, "doubleOptInEmail": { "template": "email_update_double_opt_in.htm", "subject": "Bestätigung zur Änderung Ihrer E-Mail-Adresse", "fromAddress": "noreply@meinshop.de", "fromName": "Mein Onlineshop", "enabled": false }, "errorCodes": { "missingEmail": "", "emailCheckFailed": "", "accountAlreadyExists": "", "actionNotAllowed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `verifyEmail` | object | Konfiguriert die E-Mail, über die der Kunde seine Änderung bestätigen kann.
    Betreff, Absender und Template werden über die allgemeinen E-Mail-Parameter gesteuert, siehe hier: [E-Mails & E-Mail Einstellungen](/konfiguration/e-mails-e-mail-einstellungen) | | `doubleOptInEmail` | object | Konfiguriert die optionale Double-Opt-In-Email, mit der der Kunde seine Kontolöschung vor der Ausführung bestätigen muss.
    Der Versand kann über `enabled` aktiviert oder deaktiviert werden. Betreff, Absender und Template werden über die allgemeinen E-Mail-Parameter gesteuert, siehe hier: [E-Mails & E-Mail Einstellungen](/konfiguration/e-mails-e-mail-einstellungen) | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingEmail` | string | Fehlermeldung, die ausgegeben wird, wenn keine E-Mail-Adresse übermittelt wurde.

    | | `emailCheckFailed` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene E-Mail-Adresse als ungültig bewertet wurde.

    | | `accountAlreadyExists` | string | Fehlermeldung, die ausgegeben wird, wenn ein Account mit dieser E-Mail-Adresse bereits existiert.

    | | `actionNotAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn die Aktion nicht erlaubt ist.

    | ### `actions.emailVerify` - E-Mail-Adresse bestätigen Mithilfe der Aktion `emailVerify` können Fehlermeldungen definiert werden, die auftreten, wenn ein Kunde seine E-Mail-Adresse über einen Bestätigungslink (Double-Opt-In) verifizieren soll. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "actionNotAllowed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------ | ------- | ---------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `actionNotAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn die Aktion nicht erlaubt ist.

    | ## `actions.set*` - Datenzuweisung & Aktualisierung Dieser Abschnitt umfasst Aktionen, mit denen im laufenden Shop-Kontext bestimmte Daten oder Werte gesetzt bzw. aktualisiert werden. ### `actions.setCustomerData` - Kundenzusatzdaten Mithilfe der Aktion `setCustomerData` können Fehlermeldungen bei der Verarbeitung zusätzlicher Kundendaten gesteuert werden. Diese Daten werden beispielsweise über Formulare im Kundenkonto oder im Checkout erfasst. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "fieldCheckFailed": "", "invalidNumberValue": "", "invalidCheckboxValue": "", "requiredCheckboxUnchecked": "", "requiredTextfieldEmpty": "", "requiredNumberfieldEmpty": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `fieldCheckFailed` | string | Fehlermeldung, die ausgegeben wird, wenn eine Feldprüfung fehlschlägt (beispielsweise Pflichtfeld verletzt oder Formatfehler).

    | | `invalidNumberValue` | string | Fehlermeldung, die ausgegeben wird, wenn in einem Zahlenfeld kein gültiger numerischer Wert übermittelt wurde.

    | | `invalidCheckboxValue` | string | Fehlermeldung, die ausgegeben wird, wenn für eine Checkbox ein ungültiger Wert übermittelt wurde.

    | | `requiredCheckboxUnchecked` | string | Fehlermeldung, die ausgegeben wird, wenn eine als erforderlich markierte Checkbox nicht aktiviert wurde.

    | | `requiredTextfieldEmpty` | string | Fehlermeldung, die ausgegeben wird, wenn ein erforderliches Textfeld leer gelassen wurde.

    | | `requiredNumberfieldEmpty` | string | Fehlermeldung, die ausgegeben wird, wenn ein erforderliches Zahlenfeld leer gelassen wurde.

    | ### `actions.setMainAddress` - Hauptadresse festlegen Mit der Aktion `setMainAddress` werden Fehlermeldungen definiert, die beim Festlegen der Hauptadresse im Kundenkonto auftreten. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "notLoggedIn": "", "missingAddressId": "", "invalidAddressId": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `notLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn der Benutzer nicht eingeloggt ist.

    | | `missingAddressId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Adress-ID übermittelt wurde (keine Adresse ausgewählt).

    | | `invalidAddressId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Adress-ID ungültig ist oder die Adresse nicht gefunden werden kann.

    | ## `actions.subAccountCreate` - Unterkonten (Sub-Accounts) anlegen Die Aktion `subAccountCreate` definiert Fehlermeldungen, die bei der Registrierung eines Unterkontos zu einem bestehenden Hauptkundenkonto auftreten (beispielsweise für Mitarbeiter-, Filial- oder Team-Accounts). #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "disabled": "", "notLoggedIn": "", "accountNotVerified": "", "missingId": "", "missingEmail": "", "missingPassword": "", "passwordMismatch": "", "emailCheckFailed": "", "passwordCheckFailed": "", "accountAlreadyExists": "", "mailSendFailed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `disabled` | string | Fehlermeldung, die ausgegeben wird, wenn die Anlage von Unterkonten im Shop grundsätzlich deaktiviert ist.

    | | `notLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn der Benutzer nicht eingeloggt ist.

    | | `accountNotVerified` | string | Fehlermeldung, die ausgegeben wird, wenn das Hauptkonto noch nicht verifiziert ist und deshalb keine Unterkonten anlegen darf.

    | | `missingId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Login-ID übermittelt wurde.

    | | `missingEmail` | string | Fehlermeldung, die ausgegeben wird, wenn keine E-Mail-Adresse übermittelt wurde.

    | | `missingPassword` | string | Fehlermeldung, die ausgegeben wird, wenn kein Passwort übermittelt wurde.

    | | `passwordMismatch` | string | Fehlermeldung, die ausgegeben wird, wenn Passwort und Passwort-Bestätigung nicht übereinstimmen.

    | | `emailCheckFailed` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene E-Mail-Adresse als ungültig bewertet wurde.

    | | `passwordCheckFailed` | string | Fehlermeldung, die ausgegeben wird, wenn das Passwort die Mindestanforderungen nicht erfüllt.

    | | `accountAlreadyExists` | string | Fehlermeldung, die ausgegeben wird, wenn ein Account mit dieser E-Mail-Adresse bereits existiert.

    | | `mailSendFailed` | string | Fehlermeldung, die ausgegeben wird, wenn die Einladungs-E-Mail an das neue Unterkonto nicht versendet werden konnte.

    | ## `actions.paymentVault*` - Verknüpfung mit dem Zahlungsanbieter Dieser Abschnitt umfasst die Verknüpfung des Kontos beim Zahlungsanbieter. Wenn der Kunde sich mit seinem Kundenkonto anmeldet, muss er bei Folgebestellungen die Routine auf der Seite des Zahlungsanbieters nicht erneut durchlaufen. Die hier beschriebenen Aktionen steuern die Verknüpfungen auf einer separaten Seite, die unabhängig einer Bestellung erstellt und wieder aufgehoben werden kann. Alternativ kann eine Verknüpfung auch während des Bestellprozesses entstehen. Dieser Weg läuft nicht über die hier beschriebenen Aktionen, sondern über den Bestellabschluss (siehe [actions - Warenkorb & Checkout](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout)). Welche Zahlungsarten eine Verknüpfung unterstützen, wird vom Zahlungsanbieter entschieden. Derzeit ist PayPal Checkout der einzige Anbieter, der diese Funktion unterstützt. Eine Verknüpfung wird über die Merchant-ID des Zahlungsanbieters eindeutig zugeordnet. Wenn mehrere Subshops dieselbe Merchant-ID verwenden, gilt eine einmal erstellte Verknüpfung für alle diese Subshops. Sind bei den Subshops unterschiedliche Merchant-IDs hinterlegt, müssen die Konten separat verknüpft werden. ### `actions.paymentVaultSetup` - Verknüpfung vorbereiten Mithilfe der Aktion `paymentVaultSetup` werden die Fehlermeldungen bei der Vorbereitung einer Verknüpfung des Kontos mit dem aktuellen Kundenkonto gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "unknownPaymentId": "", "failed": "", "notAllowed": "", "notLoggedIn": "", "vaultingAlreadyExists": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ----------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `unknownPaymentId` | string | Fehlermeldung, die ausgegeben wird, wenn im Formular die PaymentId fehlt, für dessen Clearer der Vault-Eintrag erstellt werden soll, oder die PaymentId unbekannt ist.

    | | `failed` | string | Fehlermeldung, die ausgegeben wird, wenn die Aktion durch interne Probleme nicht erfolgreich ausgeführt werden konnte (beispielsweise wenn der Dienstleister nicht erreichbar ist).

    | | `notAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn die Aktion nicht erlaubt ist, weil die gewählte Zahlungsart keine Verknüpfung unterstützt.

    | | `notLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn der Benutzer nicht eingeloggt ist.

    | | `vaultingAlreadyExists` | string | Fehlermeldung, die ausgegeben wird, wenn das Konto bereits verknüpft wurde.

    | ### `actions.paymentVaultCreate` - Verknüpfung erstellen Mithilfe der Aktion `paymentVaultCreate` werden die Fehlermeldungen beim Erstellen des Payment Tokens und damit der Verknüpfung gesteuert. Die Aktion setzt das über `paymentVaultSetup` erzeugte Token voraus. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "unknownPaymentId": "", "failed": "", "notAllowed": "", "notLoggedIn": "", "setupTokenMissing": "", "vaultingAlreadyExists": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ----------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `unknownPaymentId` | string | Fehlermeldung, die ausgegeben wird, wenn im Formular die PaymentId fehlt, für dessen Clearer der Vault-Eintrag erstellt werden soll, oder die PaymentId unbekannt ist.

    | | `failed` | string | Fehlermeldung, die ausgegeben wird, wenn die Aktion durch interne Probleme nicht erfolgreich ausgeführt werden konnte (beispielsweise wenn der Dienstleister nicht erreichbar ist, das übergebene Token nicht akzeptiert wird oder die Verknüpfung nicht gespeichert werden kann).

    | | `notAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn die Aktion nicht erlaubt ist, weil die gewählte Zahlungsart keine Verknüpfung unterstützt.

    | | `notLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn der Benutzer nicht eingeloggt ist.

    | | `setupTokenMissing` | string | Fehlermeldung, die ausgegeben wird, wenn in der Aktion kein Token aus `paymentVaultSetup` mitgegeben wurde.

    | | `vaultingAlreadyExists` | string | Fehlermeldung, die ausgegeben wird, wenn das Konto bereits verknüpft wurde.

    | ### `actions.paymentVaultRemove` - Verknüpfung aufheben Mithilfe der Aktion `paymentVaultRemove` werden die Fehlermeldungen beim Aufheben einer bestehenden Verknüpfung gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "unknownPaymentId": "", "failed": "", "notFound": "", "notLoggedIn": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `unknownPaymentId` | string | Fehlermeldung, die ausgegeben wird, wenn im Formular die PaymentId fehlt, für dessen Clearer die Verknüpfung aufgehoben werden soll, oder die PaymentId unbekannt ist.

    | | `failed` | string | Fehlermeldung, die ausgegeben wird, wenn die Aktion durch interne Probleme nicht erfolgreich ausgeführt werden konnte (beispielsweise wenn der Dienstleister nicht erreichbar ist oder den Widerruf ablehnt).

    | | `notFound` | string | Fehlermeldung, die ausgegeben wird, wenn keine Verknüpfung gefunden wurde. Das ist auch dann der Fall, wenn die Zahlungsart grundsätzlich keine Verknüpfung unterstützt.

    | | `notLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn der Benutzer nicht eingeloggt ist.

    | # actions - Formulare Source: https://dokumentation.websale.de/konfiguration/actions-fehlertexte-e-mails/actions-formulare Shopaktionen zum Absenden von Formularen: Konfiguration von Fehlertexten und E-Mail-Vorlagen für Kontakt-, Anfrage- und Serviceformulare im Shop. Diese Seite enthält alle Aktionen, die das Absenden von Formularen betreffen. Hier werden die zugehörigen Meldungen und E-Mail-Vorlagen dokumentiert, die beim Versenden von Formularen über den Shop ausgegeben werden – beispielsweise bei Kontakt-, Anfrage- oder Serviceformularen. ## `actions.inquirySend` - Formular absenden Mithilfe der Aktion `inquirySend` werden die Fehlermeldungen beim Absenden eines Kontakt- oder Anfrageformulars gesteuert. #### Beispielkonfiguration `actions.inquirySend` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "captchaFailed": "", "missingEmail": "", "emailCheckFailed": "", "emptyForm": "", "missingFormId": "", "invalidFormId": "", "createInquiryFailed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `captchaFailed` | string | Fehlermeldung, die ausgegeben wird, wenn die Captcha-Prüfung fehlschlägt.

    | | `missingEmail` | string | Fehlermeldung, die ausgegeben wird, wenn keine E-Mail-Adresse angegeben wurde, obwohl sie erforderlich ist.

    | | `emailCheckFailed` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene E-Mail-Adresse als ungültig erkannt wird.

    | | `emptyForm` | string | Fehlermeldung, die ausgegeben wird, wenn das abgesendete Formular leer ist.

    | | `missingFormId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Formular-ID übermittelt wurde.

    | | `invalidFormId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Formular-ID ungültig ist oder das Formular nicht gefunden werden kann.

    | | `createInquiryFailed` | string | Fehlermeldung, die ausgegeben wird, wenn die Anfrage technisch nicht gespeichert oder weitergeleitet werden konnte.

    | ## `actions.inquiryCheck` - Formular prüfen Die Aktion `inquiryCheck` überprüft den aktuellen Formularinhalt, ohne das Formular abzusenden. Dabei werden die im verknüpften `RuleSet` (siehe [inquiry - Formulare](/konfiguration/inquiry-formulare)) definierten Regeln ausgewertet und die Feld-Attribute (`$field.required`, `$field.label`, `$field.defaultValue`, `$field.value`, `$field.visible`) entsprechend aktualisiert. Beispielsweise können Felder ein- oder ausgeblendet, als Pflichtfeld markiert oder mit einem Standardwert vorbelegt werden. Die Aktion kann als Autosubmit auf dem `
    `-Element verwendet werden, sodass bei jeder Eingabeänderung automatisch eine neue Prüfung ausgelöst wird. Das Formular kann sich so dynamisch an die Eingaben des Nutzers anpassen. # actions - Newsletter Source: https://dokumentation.websale.de/konfiguration/actions-fehlertexte-e-mails/actions-newsletter Shopaktionen rund um den Newsletter: Meldungen und E-Mail-Vorlagen für Newsletter-An- und Abmeldungen sowie Einträge in Sperrlisten im WEBSALE Shop. Diese Seite enthält alle Aktionen, die den Newsletter-Versand betreffen.
    Hier finden sich alle Meldungen und E-Mail-Vorlagen für Newsletter-An- und Abmeldungen sowie für Einträge in Sperrlisten. *** ## Übersicht der Aktionen Die hier aufgeführten Aktionen wurden **thematisch gruppiert**, um die zugehörigen Fehlermeldungen und E-Mail-Vorlagen übersichtlich darzustellen. Aktionen, die inhaltlich zu einem anderen Themenbereich gehören, finden sich in den entsprechenden Abschnitten dieser Dokumentation oder in der [alphabetischen Übersicht der Aktionen](/konfiguration/actions-fehlertexte-e-mails/actions-alphabetische-ubersicht). #### Auszug der Grundstruktur `actions` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "actions": { ... "blacklistAdd": {...}, "newsletterSubscribe": {...}, "newsletterUnsubscribe": {...}, ... } } ``` #### Aktionsübersicht | **Aktion** | **Beschreibung** | | ----------------------- | ------------------------------------------------------------------------------------------------------ | | `blacklistAdd` | Definiert die Fehlermeldungen, die beim Hinzufügen eines Kundenkontos zur Blacklist ausgegeben werden. | | `newsletterSubscribe` | Definiert die Fehlermeldungen, die bei der Anmeldung zum Newsletter ausgegeben werden. | | `newsletterUnsubscribe` | Definiert die Fehlermeldungen, die bei der Abmeldung vom Newsletter ausgegeben werden. | *** ## `actions.blacklistAdd` - Empfänger einer Blacklist hinzufügen Mit der Aktion `blacklistAdd` werden die Fehlermeldungen definiert, die beim Hinzufügen einer E-Mail-Adresse zur Blacklist (Sperrliste) ausgegeben werden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingEmail": "", "emailCheckFailed": "", "actionNotAllowed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingEmail` | string | Fehlermeldung, die ausgegeben wird, wenn keine E-Mail-Adresse übermittelt wurde.

    | | `emailCheckFailed` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene E-Mail-Adresse als ungültig bewertet wurde.

    | | `actionNotAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn die Aktion nicht erlaubt ist.

    | *** ## `actions.newsletter*` - Newsletter ### `actions.newsletterSubscribe` - Newsletteranmeldung Mit der Aktion `newsletterSubscribe` werden Fehlermeldungen definiert, die bei der Anmeldung zum Newsletter ausgegeben werden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingField": "", "invalidField": "", "invalidTargetGroupId": "", "deactivatedTargetGroup": "", "actionNotAllowed": "", "emailCheckFailed": "", "internalError": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingField` | string | Fehlermeldung, die ausgegeben wird, wenn mindestens ein erforderliches Feld nicht ausgefüllt wurde.

    | | `invalidField` | string | Fehlermeldung, die ausgegeben wird, wenn ein Feld einen ungültigen Wert enthält.

    | | `invalidTargetGroupId` | string | Fehlermeldung, die ausgegeben wird, wenn eine ungültige oder unbekannte Newsletter-Zielgruppe übermittelt wurde.

    | | `deactivatedTargetGroup` | string | Fehlermeldung, die ausgegeben wird, wenn die gewünschte Newsletter-Zielgruppe im System deaktiviert ist.

    | | `actionNotAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn die Aktion nicht erlaubt ist.

    | | `emailCheckFailed` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene E-Mail-Adresse als ungültig bewertet wurde.

    | | `internalError` | string | Fehlermeldung, die ausgegeben wird, wenn unerwartete Systemfehler während der Anmeldung zum Newsletter auftreten.

    | ### `actions.newsletterUnsubscribe` - Newsletterabmeldung Mit der Aktion `newsletterUnsubscribe` werden die Fehlermeldungen definiert, die bei der Abmeldung vom Newsletter ausgegeben werden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingEmail": "", "missingField": "", "missingTargetGroupId": "", "invalidTargetGroupId": "", "actionNotAllowed": "", "internalError": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingEmail` | string | Fehlermeldung, die ausgegeben wird, wenn keine E-Mail-Adresse übermittelt wurde.

    | | `missingField` | string | Fehlermeldung, die ausgegeben wird, wenn ein erforderliches Feld nicht ausgefüllt wurde.

    | | `missingTargetGroupId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Newsletter-Gruppe zur Abmeldung angegeben wurde.

    | | `invalidTargetGroupId` | string | Fehlermeldung, die ausgegeben wird, wenn eine ungültige oder unbekannte Newsletter-Zielgruppe übermittelt wurde.

    | | `actionNotAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn die Aktion nicht erlaubt ist.

    | | `internalError` | string | Fehlermeldung, die ausgegeben wird, wenn unerwartete Systemfehler während der Abmeldung vom Newsletter auftreten.

    | # actions - Produkte Source: https://dokumentation.websale.de/konfiguration/actions-fehlertexte-e-mails/actions-produkte Shopaktionen zu Produkten: Konfiguration der Meldungen für Bewertungen, Merklisten und Verfügbarkeitsalarme inklusive zugehöriger Benachrichtigungen. Diese Seite enthält alle Aktionen, die im Zusammenhang mit Produkten stehen.\ Hierzu gehören Aktionen für Bewertungen, Merklisten und Verfügbarkeitsalarme sowie die zugehörigen Meldungen und Benachrichtigungen. *** ## Übersicht der Aktionen Die hier aufgeführten Aktionen wurden **thematisch gruppiert**, um die zugehörigen Fehlermeldungen und E-Mail-Vorlagen übersichtlich darzustellen. Aktionen, die inhaltlich zu einem anderen Themenbereich gehören, finden sich in den entsprechenden Abschnitten dieser Dokumentation oder in der [alphabetischen Übersicht der Aktionen](/konfiguration/actions-fehlertexte-e-mails/actions-alphabetische-ubersicht). #### Auszug der Grundstruktur `actions` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "actions": { ... "backInStockActivate": {...}, "backInStockDeactivate": {...}, "productRatingAdd": {...}, "productRatingDelete": {...}, "productRatingUpdate": {...}, "watchListAdd": {...}, "watchListDelete": {...}, "watchListItemAdd": {...}, "watchListItemDelete": {...}, ... } } ``` #### Aktionsübersicht | **Aktion** | **Beschreibung** | | ----------------------- | ----------------------------------------------------------------------------------------------------------------------- | | `backInStockActivate` | Definiert die Fehlermeldungen, die bei Anfragen zur Aktivierung einer Verfügbarkeitsbenachrichtigung ausgegeben werden. | | `backInStockDeactivate` | Definiert die Fehlermeldung, die bei Deaktivierung einer Verfügbarkeitsbenachrichtigung ausgegeben werden. | | `productRatingAdd` | Definiert die Fehlermeldungen, die beim Abgeben einer Produktbewertung ausgegeben werden. | | `productRatingUpdate` | Definiert die Fehlermeldungen, die beim Ändern einer Produktbewertung ausgegeben werden. | | `productRatingDelete` | Definiert die Fehlermeldungen, die beim Löschen einer Produktbewertung ausgegeben werden. | | `watchListAdd` | Definiert die Fehlermeldungen, die beim Anlegen und verwenden von Merklisten ausgegeben werden. | | `watchListDelete` | Definiert die Fehlermeldungen, die beim Löschen einer Merkliste ausgegeben werden. | | `watchListItemAdd` | Definiert die Fehlermeldungen, die beim Hinzufügen von Produkten zur Merkliste ausgegeben werden. | | `watchListItemDelete` | Definiert die Fehlermeldungen, die beim Entfernen eines Artikels aus der Merkliste ausgegeben werden. | *** ## `actions.backInStock*` - Verfügbarkeitsalarm ### `actions.backInStockActivate` - Verfügbarkeitsalarm aktivieren Mithilfe der Aktion `backInStockActivate` werden Fehlermeldungen bei Anfragen zur Aktivierung einer Verfügbarkeitsbenachrichtigung gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "notLoggedIn": "", "missingEmail": "", "missingProductId": "", "invalidStoreId": "", "internError": "", "notAllowed": "", "missingInventoryState": "", "entryExists": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ----------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | array | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `notLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn der Benutzer nicht eingeloggt ist.

    | | `missingEmail` | string | Fehlermeldung, die ausgegeben wird, wenn keine E-Mail-Adresse übermittelt wurde.

    | | `missingProductId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Produkt-ID angegeben wurde, für die die Benachrichtigung eingerichtet werden soll.

    | | `invalidStoreId` | string | Fehlermeldung, die ausgegeben wird, wenn eine ungültige oder unbekannte Store-/Filial-ID übermittelt wurde.

    | | `internError` | string | Fehlermeldung, die ausgegeben wird, wenn ein unerwarteter Systemfehler während der Aktivierung der Benachrichtigung auftritt.

    | | `notAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn die Aktion nicht erlaubt ist.

    | | `missingInventoryState` | string | Fehlermeldung, die ausgegeben wird, wenn für das Produkt kein Lagerstatus vorliegt.

    | | `entryExists` | string | Fehlermeldung, die ausgegeben wird, wenn bereits ein Eintrag für eine Verfügbarkeitsbenachrichtigung zu diesem Artikel und für diesen Kunden existiert.

    | ### `actions.backInStockDeactivate` - Verfügbarkeitsalarm deaktivieren Mithilfe der Aktion `backInStockDeactivate` werden Fehlermeldungen für Anfragen zur Deaktivierung einer Verfügbarkeitsbenachrichtigung gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "notLoggedIn": "", "missingEmail": "", "missingProductId": "", "internError": "", "notAllowed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------ | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | array | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `notLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn der Benutzer nicht eingeloggt ist.

    | | `missingEmail` | string | Fehlermeldung, die ausgegeben wird, wenn keine E-Mail-Adresse übermittelt wurde.

    | | `missingProductId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Produkt-ID angegeben wurde, für die die Benachrichtigung deaktiviert werden soll.

    | | `internError` | string | Fehlermeldung, die ausgegeben wird, wenn ein unerwarteter Systemfehler während der Deaktivierung der Benachrichtigung auftritt.

    | | `notAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn die Aktion nicht erlaubt ist.

    | *** ## `actions.productRating*` - Produktbewertung ### `actions.productRatingAdd` - Produkt bewerten Mithilfe der Aktion `productRatingAdd` werden Fehlermeldungen beim Abgeben einer Produktbewertung gesteuert. Zusätzlich kann über `merchantEmail` eine E-Mail an den Händler konfiguriert werden, die über neue Bewertungen informiert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingProductId": "", "missingOrderId": "", "wrongProductId": "", "wrongOrderId": "", "userMustLoggedIn": "", "invalidPoints": "", "missingPoints": "", "missingSubject": "", "missingDescription": "", "duplicateRating": "", "multiRating": "", "maxLengthSubject": "", "maxLengthDescription": "", "productNotExists": "", "orderNotExists": "" }, "merchantEmail": { "template": "product_rating_merchant_notify.htm", "subject": "Neue Produktbewertung im Shop", "fromAddress": "noreply@meinshop.de", "fromName": "Mein Onlineshop", "toAddress": "bewertung@meinshop.de" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | array | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingProductId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Produkt-ID angegeben wurde, für die eine Bewertung abgegeben werden soll.

    | | `missingOrderId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Bestellnummer/Order-ID angegeben wurde.

    | | `wrongProductId` | string | Fehlermeldung, die ausgegeben wird, wenn das bewertete Produkt nicht zur angegebenen Bestellung gehört.

    | | `wrongOrderId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Bestellung nicht zum erwarteten Kontext passt (z.B. nicht dem Kunden zugeordnet).

    | | `userMustLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn ein nicht angemeldeter Benutzer eine Bewertung abgeben möchte.

    | | `invalidPoints` | string | Fehlermeldung, die ausgegeben wird, wenn eine ungültige Punkteanzahl übermittelt wird.

    | | `missingPoints` | string | Fehlermeldung, die ausgegeben wird, wenn keine Punktebewertung angegeben wurde.

    | | `missingSubject` | string | Fehlermeldung, die ausgegeben wird, wenn kein Titel für die Bewertung angegeben wurde.

    | | `missingDescription` | string | Fehlermeldung, die ausgegeben wird, wenn kein Bewertungstext übermittelt wurde.

    | | `duplicateRating` | string | Fehlermeldung, die ausgegeben wird, wenn für dieses Produkt bereits eine Bewertung desselben Kunden existiert.

    | | `multiRating` | string | Fehlermeldung, die ausgegeben wird, wenn mehrere Bewertungen in einem unerlaubten Kontext abgegeben wurden (z.B. doppelte Einträge).

    | | `maxLengthSubject` | string | Fehlermeldung, die ausgegeben wird, wenn beim Titel der Bewertung die maximale Zeichenlänge überschritten wurde.

    | | `maxLengthDescription` | string | Fehlermeldung, die ausgegeben wird, wenn der Bewertungstext die maximal zulässige Länge überschreitet.

    | | `productNotExists` | string | Fehlermeldung, die ausgegeben wird, wenn die übermittelte Produkt-ID im System nicht gefunden wird.

    | | `orderNotExists` | string | Fehlermeldung, die ausgegeben wird, wenn die übermittelte Order-ID im System nicht gefunden wird.

    | | `merchantEmail` | object | Konfiguriert die E-Mail, über die der Händler über eine abgegebene Bewertung zu seinem Produkt informiert wird.
    Betreff, Absender und Template werden über die allgemeinen E-Mail-Parameter gesteuert, siehe hier: [E-Mail Einstellungen](/konfiguration/e-mails-e-mail-einstellungen) | ### `actions.productRatingDelete` - Produktbewertung löschen Mithilfe der Aktion `productRatingDelete` werden Fehlermeldungen beim Löschen einer Produktbewertung gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingProductId": "", "missingOrderId": "", "wrongProductId": "", "wrongOrderId": "", "userMustLoggedIn": "", "productNotExists": "", "invalidPoints": "", "missingPoints": "", "missingSubject": "", "missingDescription": "", "duplicateRating": "", "multiRating": "", "maxLengthSubject": "", "maxLengthDescription": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | array | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingProductId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Produkt-ID angegeben wurde, für die eine Bewertung gelöscht werden soll.

    | | `missingOrderId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Bestellnummer/Order-ID angegeben wurde.

    | | `wrongProductId` | string | Fehlermeldung, die ausgegeben wird, wenn das bewertete Produkt nicht zur angegebenen Bestellung gehört.

    | | `wrongOrderId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Bestellung nicht zum erwarteten Kontext passt (z.B. nicht dem Kunden zugeordnet).

    | | `userMustLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn ein nicht angemeldeter Benutzer eine Bewertung löschen möchte.

    | | `invalidPoints` | string | Fehlermeldung, die ausgegeben wird, wenn eine ungültige Punktezahl übermittelt wird.

    | | `missingPoints` | string | Fehlermeldung, die ausgegeben wird, wenn keine Punktebewertung angegeben wurde.

    | | `missingSubject` | string | Fehlermeldung, die ausgegeben wird, wenn kein Titel für die Bewertung angegeben wurde.

    | | `missingDescription` | string | Fehlermeldung, die ausgegeben wird, wenn kein Bewertungstext übermittelt wurde.

    | | `duplicateRating` | string | Fehlermeldung, die ausgegeben wird, wenn für dieses Produkt bereits eine Bewertung desselben Kunden existiert.

    | | `multiRating` | string | Fehlermeldung, die ausgegeben wird, wenn mehrere Bewertungen in einem unerlaubten Kontext gelöscht wurden (z.B. doppelte Einträge).

    | | `maxLengthSubject` | string | Fehlermeldung, die ausgegeben wird, wenn beim Titel der Bewertung die maximale Zeichenlänge überschritten wurde.

    | | `maxLengthDescription` | string | Fehlermeldung, die ausgegeben wird, wenn der Bewertungstext die maximal zulässige Länge überschreitet.

    | | `productNotExists` | string | Fehlermeldung, die ausgegeben wird, wenn die übermittelte Produkt-ID im System nicht gefunden wird.

    | ### `actions.productRatingUpdate` - Produktbewertung ändern Mithilfe der Aktion `productRatingUpdate` werden die Fehlermeldungen für Anfragen zur Bearbeitung einer bestehenden Produktbewertung gesteuert. #### Beispielkonfiguration `actions.productRatingUpdate` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingProductId": "", "missingOrderId": "", "missingSubject": "", "missingDescription": "", "invalidPoints": "", "missingPoints": "", "userMustLoggedIn": "", "productNotExists": "", "duplicateRating": "", "multiRating": "", "maxLengthSubject": "", "maxLengthDescription": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | array | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingProductId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Produkt-ID angegeben wurde, für die eine Bewertung geändert werden soll.

    | | `missingOrderId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Bestellnummer/Order-ID angegeben wurde.

    | | `userMustLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn ein nicht angemeldeter Benutzer eine Bewertung ändern möchte.

    | | `invalidPoints` | string | Fehlermeldung, die ausgegeben wird, wenn eine ungültige Punkteanzahl übermittelt wird.

    | | `missingPoints` | string | Fehlermeldung, die ausgegeben wird, wenn keine Punktebewertung angegeben wurde.

    | | `missingSubject` | string | Fehlermeldung, die ausgegeben wird, wenn kein Titel für die Bewertung angegeben wurde.

    | | `missingDescription` | string | Fehlermeldung, die ausgegeben wird, wenn kein Bewertungstext übermittelt wurde.

    | | `duplicateRating` | string | Fehlermeldung, die ausgegeben wird, wenn für dieses Produkt bereits eine Bewertung desselben Kunden existiert.

    | | `multiRating` | string | Fehlermeldung, die ausgegeben wird, wenn mehrere Bewertungen in einem unerlaubten Kontext geändert wurden (z.B. doppelte Einträge).

    | | `maxLengthSubject` | string | Fehlermeldung, die ausgegeben wird, wenn beim Titel der Bewertung die maximale Zeichenlänge überschritten wurde.

    | | `maxLengthDescription` | string | Fehlermeldung, die ausgegeben wird, wenn der Bewertungstext die maximal zulässige Länge überschreitet.

    | | `productNotExists` | string | Fehlermeldung, die ausgegeben wird, wenn die übermittelte Produkt-ID im System nicht gefunden wird.

    | *** ## `actions.watchList*` - Merkliste ### `actions.watchListAdd` - Merkliste anlegen / hinzufügen Mithilfe der Aktion `watchListAdd` werden die Fehlermeldungen beim Anlegen und Verwenden von Merklisten gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "defaultWatchlist": "Meine Merkliste", "basketWatchlist": "Aus dem Warenkorb gemerkt", "errorCodes": { "missingWatchListName": "", "invalidWatchListName": "", "missingWatchListId": "", "watchListNotFound": "", "notLoggedIn": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `defaultWatchlist` | string | Anzeigename der Standard-Merkliste, zu der Produkte ohne spezielle Auswahl hinzugefügt werden.
    Default: "`Default Watchlist`" | | `basketWatchlist` | string | Anzeigename der Merkliste, die für aus dem Warenkorb übernommene Produkte verwendet werden kann.
    Default: "`Basket Watchlist`" | | `errorCodes` | array | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingWatchListName` | string | Fehlermeldung, die ausgegeben wird, wenn kein Name für eine neue oder umzubenennende Merkliste übermittelt wurde.

    | | `invalidWatchListName` | string | Fehlermeldung, die ausgegeben wird, wenn der angegebene Merklistenname ungültig ist.

    | | `missingWatchListId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Merklisten-ID übermittelt wurde, obwohl eine bestehende Merkliste erwartet wurde.

    | | `watchListNotFound` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Merkliste im System nicht gefunden werden kann.

    | | `notLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn ein nicht angemeldeter Benutzer versucht, Produkte zur Merkliste hinzuzufügen.

    | ### `actions.watchListDelete` - Merkliste löschen / entfernen Mithilfe der Aktion `watchListDelete` werden die Fehlermeldungen beim Löschen einer Merkliste gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingWatchListName": "", "invalidWatchListName": "", "missingWatchListId": "", "watchListNotFound": "", "notLoggedIn": "", "notChangeable": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | array | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingWatchListName` | string | Fehlermeldung, die ausgegeben wird, wenn der angegebene Merklistenname ungültig ist.

    | | `invalidWatchListName` | string | Fehlermeldung, die ausgegeben wird, wenn der angegebene Merklistenname ungültig ist.

    | | `missingWatchListId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Merklisten-ID übermittelt wurde, obwohl eine bestehende Merkliste erwartet wurde.

    | | `watchListNotFound` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Merkliste im System nicht gefunden werden kann.

    | | `notLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn ein nicht angemeldeter Benutzer versucht, eine Merkliste zu löschen.

    | | `notChangeable` | string | Fehlermeldung, die ausgegeben wird, wenn die ausgewählte Merkliste nicht löschbar ist (z.B. die Standardliste).

    | ### `actions.watchListItemAdd` - Produkt einer Merkliste hinzufügen Mithilfe der Aktion `watchListItemAdd` werden die Fehlermeldungen beim Hinzufügen von Produkten zur Merkliste gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingProductId": "", "invalidProductId": "", "invalidVariantId": "", "invalidService": "", "watchListNotFound": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `errorCodes` | array | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingProductId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Produkt-ID übermittelt wurde.

    | | `invalidProductId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Produkt-ID ungültig ist oder der Artikel nicht gefunden werden konnte.

    | | `invalidVariantId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Variante ungültig oder nicht verfügbar ist.

    | | `invalidService` | string | Fehlermeldung, die ausgegeben wird, wenn ein ungültiger oder für den Artikel nicht gültiger Zusatzservice übermittelt wurde.

    | | `watchListNotFound` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Merkliste im System nicht gefunden werden kann.

    | ### `actions.watchListItemDelete` - Produkt von einer Merkliste löschen Mithilfe der Aktion `watchListItemDelete` werden die Fehlermeldungen beim Entfernen eines Artikels aus einer Merkliste gesteuert. #### Beispielkonfiguration `actions.watchListItemDelete` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingItemId": "", "invalidItemId": "", "missingWatchListId": "", "invalidService": "", "watchListNotFound": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | -------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | array | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingItemId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Item-/Positions-ID übermittelt wurde (kein konkreter Merklisten-Eintrag ausgewählt).

    | | `invalidItemId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Item-ID ungültig ist oder der Eintrag nicht gefunden werden kann.

    | | `missingWatchListId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Merklisten-ID angegeben wurde.

    | | `invalidService` | string | Fehlermeldung, die ausgegeben wird, wenn ein ungültiger oder nicht passender Service-Kontext für den Merklisten-Eintrag verwendet wird.

    | | `watchListNotFound` | string | Fehlermeldung, die ausgegeben wird, wenn die referenzierte Merkliste im System nicht existiert.

    | # actions - Sicherheit & Datenschutz Source: https://dokumentation.websale.de/konfiguration/actions-fehlertexte-e-mails/actions-sicherheit-datenschutz Shopaktionen für Sicherheit und Datenschutz: Meldungen und Benachrichtigungen rund um Sitzungssteuerung sowie Consent Layer zur Einwilligungsverwaltung. Diese Seite enthält alle Aktionen, die die Sicherheit und den Datenschutz im Shop betreffen. Dazu zählen Meldungen und Benachrichtigungen rund um die Sitzungssteuerung und den Consent Layer zur Verwaltung von Einwilligungen. *** ## Übersicht der Aktionen Die hier aufgeführten Aktionen wurden **thematisch gruppiert**, um die zugehörigen Fehlermeldungen und E-Mail-Vorlagen übersichtlich darzustellen. Aktionen, die inhaltlich zu einem anderen Themenbereich gehören, finden sich in den entsprechenden Abschnitten dieser Dokumentation oder in der [alphabetischen Übersicht der Aktionen](/konfiguration/actions-fehlertexte-e-mails/actions-alphabetische-ubersicht). #### Auszug der Grundstruktur `actions` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "actions": { ... "sessionUnlock": {...}, "sessionUpdate": {...}, "consentChange": {...}, ... } } ``` #### Aktionsübersicht | **Aktion** | **Beschreibung** | | --------------- | -------------------------------------------------------- | | `sessionUnlock` | Steuert, ob das Entsperren einer Session möglich ist. | | `sessionUpdate` | Steuert, ob das Aktualisieren einer Session möglich ist. | | `consentChange` | Steuert, ob das Ändern einer Einwilligung verfügbar ist. | *** ## `actions.session*` - Sitzung des Shops ### `actions.sessionUnlock` - Sitzung entsperren Mithilfe der Aktion `sessionUnlock` wird gesteuert, ob das Entsperren einer Session durch den Benutzer möglich ist oder nicht. #### Beispielkonfiguration `actions.sessionUnlock` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `active` | bool | Aktiviert/deaktiviert die Aktion `sessionUnlock`.
    Wenn `false`, ist das Entsperren der Session über diese Aktion nicht verfügbar.
    Default: `true` | ### `actions.sessionUpdate` - Sitzungsdaten aktualisieren Mithilfe der Aktion `sessionUpdate` wird gesteuert, ob das Aktualisieren einer Session möglich ist. #### Beispielkonfiguration `actions.sessionUpdate` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `active` | bool | Aktiviert/deaktiviert die Aktion `sessionUpdate`.
    Wenn `false`, ist das Aktualisieren der Session über diese Aktion nicht verfügbar.
    Default: `true` | *** ## `actions.consentChange` - Consent-Einstellungen ändern Mithilfe der Aktion `consentChange` wird gesteuert, ob das Ändern einer Einwilligung (Consent) möglich ist. Die grundlegenden Einstellungen für den Consent Layer – beispielsweise Gruppierungen, Kategorien und Definitionen zustimmungspflichtiger Dienste – werden im Konfigurationsbereich [general.consentCookie\*](/konfiguration/general-allgemeine-shopeinstellungen) vorgenommen. #### Beispielkonfiguration `actions.consentChange` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `active` | bool | Aktiviert/deaktiviert die Aktion `consentChange`.
    Wenn `false`, ist das Ändern der Einwilligung über diese Aktion nicht verfügbar.
    Default: `true` | *** # actions - Testmodus Source: https://dokumentation.websale.de/konfiguration/actions-fehlertexte-e-mails/actions-testmodus Shopaktionen zur Steuerung des Testmodus: Konfiguration zum Aktivieren, Deaktivieren oder Umschalten des Testmodus im WEBSALE Shopsystem. Dieser Bereich umfasst alle Aktionen, die zur Steuerung des Testmodus dienen. Sie ermöglichen das Aktivieren, Deaktivieren oder Umschalten des Testmodus innerhalb des Systems. ## `actions.testMode*` - Testmodus Die hier aufgeführten Aktionen wurden **thematisch gruppiert**, um die zugehörigen Fehlermeldungen und E-Mail-Vorlagen übersichtlich darzustellen. Aktionen, die inhaltlich zu einem anderen Themenbereich gehören, finden sich in den entsprechenden Abschnitten dieser Dokumentation oder in der [alphabetischen Übersicht der Aktionen](/konfiguration/actions-fehlertexte-e-mails/actions-alphabetische-ubersicht). #### Auszug der Grundstruktur `actions` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "actions": { ... "testModeChange": {...}, "testModeOff": {...}, "testModeOn": {...}, ... } } ``` #### Aktionsübersicht | **Aktion** | **Beschreibung** | | ---------------- | ----------------------------------------------------------------------------------------------- | | `testModeOn` | Definiert die Fehlermeldungen, die bei Anfragen zum Aktivieren des Testmodus ausgegeben werden. | | `testModeOff` | Definiert die Fehlermeldung, die bei Anfragen zum Deaktivieren des Testmodus ausgegeben werden. | | `testModeChange` | Definiert die Fehlermeldungen, die bei Anfragen zum Ändern des Testmodus ausgegeben werden. | ### `actions.testModeChange` - Testmodus ändern Mithilfe der Aktion `testModeChange` werden die Fehlermeldungen für Anfragen zur Änderung des Testmodus gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "notAllowed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `notAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn das Ändern des Testmodus im aktuellen Kontext nicht erlaubt ist.

    | ### `actions.testModeOff` - Testmodus deaktivieren / ausschalten Mithilfe der Aktion `testModeOff` werden die Fehlermeldungen für Anfragen zur Deaktivierung des Testmodus gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "notAllowed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `notAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn das Deaktivieren des Testmodus im aktuellen Kontext nicht erlaubt ist.

    | ### `actions.testModeOn` - Testmodus aktivieren / einschalten Mithilfe der Aktion `testModeOn` werden die Fehlermeldungen für Anfragen zur Aktivierung des Testmodus gesteuert. #### Beispielkonfiguration `actions.testModeOn` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "noPassword": "", "invalidPassword": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ----------------- | ------- | -------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `noPassword` | string | Fehlermeldung, die ausgegeben wird, wenn kein Passwort übermittelt wurde.

    | | `invalidPassword` | string | Fehlermeldung, die ausgegeben wird, wenn das übermittelte Passwort ungültig ist.

    | # actions - Warenkorb & Checkout Source: https://dokumentation.websale.de/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout Shopaktionen während Warenkorb und Bestellvorgang: Meldungen und E-Mail-Vorlagen für Artikel-Updates, Bestellabschluss und Gastregistrierungen. Diese Seite enthält alle Aktionen, die während des Bestellvorgangs im Shop ausgeführt werden.
    Hier finden sich die zugehörigen Meldungen und E-Mail-Vorlagen, die beim Hinzufügen, Entfernen oder Aktualisieren von Artikeln sowie beim Abschluss einer Bestellung oder bei Gastregistrierungen verwendet werden. ## Übersicht der Aktionen Die hier aufgeführten Aktionen wurden **thematisch gruppiert**, um die zugehörigen Fehlermeldungen und E-Mail-Vorlagen übersichtlich darzustellen. Aktionen, die inhaltlich zu einem anderen Themenbereich gehören, finden sich in den entsprechenden Abschnitten dieser Dokumentation oder in der [alphabetischen Übersicht der Aktionen](/konfiguration/actions-fehlertexte-e-mails/actions-alphabetische-ubersicht). #### Auszug der Grundstruktur `actions` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "actions": { ... "basketItemAdd": {...}, "basketItemDelete": {...}, "basketItemUpdate": {...}, "checkoutAccountTypeSelect": {...}, "checkoutBillAddressSelect": {...}, "checkoutConfirm": {...}, "checkoutPaymentUpdate": {...}, "checkoutPseudoCCSelect": {...}, "checkoutSetFreeFields": {...}, "checkoutSetGuestEmail": {...}, "checkoutShippingAddressSelect": {...}, "checkoutShippingMethodUpdate": {...}, "checkoutUseDifferentShippingAddress": {...}, "guestRegister": {...}, "directOrder": {...}, "voucherAdd": {...}, "voucherDelete": {...}, "inventoryReserve": {...}, ... } } ``` #### Aktionsübersicht | **Aktion** | **Beschreibung** | | ------------------------------- | ---------------------------------------------------------------------------------------------- | | `basketItemAdd` | Definiert Fehlermeldungen beim Hinzufügen eines Artikels zum Warenkorb. | | `basketItemDelete` | Definiert Fehlermeldungen beim Entfernen eines Artikels aus dem Warenkorb. | | `basketItemUpdate` | Definiert Fehlermeldungen beim Ändern einer Warenkorbposition. | | `checkoutAccountTypeSelect` | Definiert Fehlermeldungen der Auswahl des Konto-Typs im Checkout. | | `checkoutBillAddressSelect` | Definiert Fehlermeldungen bei der Auswahl der Rechnungsadresse im Checkout. | | `checkoutConfirm` | Definiert E-Mails und Fehlermeldungen für den Bestellabschluss. | | `checkoutPaymentUpdate` | Definiert Fehlermeldungen beim Ändern der Zahlungsart im Checkout. | | `checkoutPseudoCCSelect` | Definiert Fehlermeldungen beim Auswählen einer gespeicherten (Pseudo-)Kreditkarte im Checkout. | | `checkoutSetFreeFields` | Definiert Fehlermeldungen bei der Prüfung von Freitextfeldern im Checkout. | | `checkoutSetGuestEmail` | Definiert Fehlermeldungen bei der Eingabe der E-Mail-Adresse für eine Gastbestellung. | | `checkoutShippingAddressSelect` | Definiert die Fehlermeldungen bei der Auswahl der Lieferadresse im Checkout. | | `checkoutShippingMethodUpdate` | Definiert Fehlermeldungen beim Ändern der Versandart im Checkout. | | `guestRegister` | Definiert E-Mails und Fehlermeldungen für das Anlegen eines Kundenkontos nach Gastbestellung. | | `directOrder` | Definiert Fehlermeldungen für Direktbestellungen. | | `voucherAdd` | Definiert Fehlermeldungen beim Hinzufügen eines Gutscheins zum Warenkorb. | | `voucherDelete` | Definiert Fehlermeldungen beim Entfernen eines Gutscheins aus dem Warenkorb. | | `inventoryReserve` | Definiert Fehlermeldungen beim Reservieren von Lagerbestand für Warenkorbpositionen. | ## `actions.basketItem*` - Warenkorbposition ### `actions.basketItemAdd` - Warenkorbposition hinzufügen Mithilfe der Aktion `basketItemAdd` werden die Fehlermeldungen beim Hinzufügen eines Artikels in den Warenkorb gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "accountNotVerified": "", "basketLocked": "", "missingProductId": "", "missingQuantity": "", "invalidQuantity": "", "invalidProductId": "", "invalidVariantId": "", "insufficientAmount": "", "quantityExceeded": "", "childProductOnly": "", "expressCheckoutNotAllowed": "", "noVariantFound": "", "invalidStore": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `accountNotVerified` | string | Fehlermeldung, die ausgegeben wird, wenn das Kundenkonto noch nicht verifiziert wurde.

    | | `basketLocked` | string | Fehlermeldung, die ausgegeben wird, wenn der Warenkorb gesperrt ist und derzeit nicht verändert werden kann (beispielsweise während eines laufenden Express-Checkouts).

    | | `missingProductId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Produkt-ID übermittelt wurde.

    | | `missingQuantity` | string | Fehlermeldung, die ausgegeben wird, wenn keine Bestellmenge angegeben wurde.

    | | `invalidQuantity` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Bestellmenge ungültig ist.

    | | `invalidProductId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Produkt-ID ungültig ist.

    | | `invalidVariantId` | string | Fehlermeldung, die ausgegeben wird, wenn die gewählte Variante ungültig oder nicht verfügbar ist.

    | | `insufficientAmount` | string | Fehlermeldung, die ausgegeben wird, wenn nicht genügend Bestand für die gewünschte Menge vorhanden ist.

    | | `quantityExceeded` | string | Fehlermeldung, die ausgegeben wird, wenn eine definierte maximale Bestellmenge überschritten wird.

    | | `childProductOnly` | string | Fehlermeldung, die ausgegeben wird, wenn versucht wird, ein Produkt direkt zu bestellen, das nur als "Child"-Produkt konfigurierbar ist.

    | | `expressCheckoutNotAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn der Artikel im Express-Checkout nicht in den Warenkorb gelegt werden darf.

    | | `noVariantFound` | string | Fehlermeldung, die ausgegeben wird, wenn zu den gewählten Optionen keine passende Produktvarianten gefunden wird.

    | | `invalidStore` | string | Fehlermeldung, die ausgegeben wird, wenn der gewählte Abholort für den Artikel ungültig oder nicht verfügbar ist.

    | ### `actions.basketItemDelete` - Warenkorbposition löschen Mithilfe der Aktion `basketItemDelete` werden die Fehlermeldungen beim Entfernen eines Artikels aus dem Warenkorb gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "accountNotVerified": "", "basketLocked": "", "missingBasketItemId": "", "invalidBasketItemId": "", "basketItemIsSetChild": "", "itemNotRemovable": "", "internalError": "", "invalidChildItem": "", "expressCheckoutNotAllowed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `accountNotVerified` | string | Fehlermeldung, die ausgegeben wird, wenn das Kundenkonto noch nicht verifiziert wurde.

    | | `basketLocked` | string | Fehlermeldung, die ausgegeben wird, wenn der Warenkorb gesperrt ist und derzeit nicht verändert werden kann (beispielsweise während eines laufenden Express-Checkouts).

    | | `missingBasketItemId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Warenkorbpositions-ID übermittelt wurde.

    | | `invalidBasketItemId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Warenkorbposition ungültig ist oder nicht gefunden werden kann.

    | | `basketItemIsSetChild` | string | Fehlermeldung, die ausgegeben wird, wenn versucht wird, eine Variante zu entfernen, die nur über das Hauptprodukt entfernt werden darf.

    | | `itemNotRemovable` | string | Fehlermeldung, die ausgegeben wird, wenn die betreffende Position grundsätzlich nicht entfernt werden darf.

    | | `internalError` | string | Fehlermeldung, die ausgegeben wird, wenn ein unerwarteter Systemfehler auftritt.

    | | `invalidChildItem` | string | Fehlermeldung, die ausgegeben wird, wenn eine ungültige Variante referenziert wird.

    | | `expressCheckoutNotAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn das Entfernen der Position im Rahmen eines Express-Checkout nicht erlaubt ist.

    | ### `actions.basketItemUpdate` - Warenkorbposition ändern Mithilfe der Aktion `basketItemUpdate` werden die Fehlermeldungen beim Ändern einer Warenkorbposition gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "accountNotVerified": "", "basketLocked": "", "missingBasketItemId": "", "missingQuantity": "", "invalidBasketItemId": "", "invalidQuantity": "", "invalidProductId": "", "invalidVariantId": "", "insufficientAmount": "", "quantityExceeded": "", "childProductOnly": "", "itemNotChangeable": "", "internalError": "", "invalidChildItem": "", "expressCheckoutNotAllowed": "", "noVariantFound": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `accountNotVerified` | string | Fehlermeldung, die ausgegeben wird, wenn das Kundenkonto noch nicht verifiziert wurde.

    | | `basketLocked` | string | Fehlermeldung, die ausgegeben wird, wenn der Warenkorb gesperrt ist und derzeit nicht verändert werden kann (beispielsweise während eines laufenden Express-Checkouts).

    | | `missingBasketItemId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Warenkorbpositions-ID übermittelt wurde.

    | | `missingQuantity` | string | Fehlermeldung, die ausgegeben wird, wenn keine Bestellmenge angegeben wurde.

    | | `invalidBasketItemId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Warenkorbposition ungültig ist oder nicht gefunden werden kann.

    | | `invalidQuantity` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Bestellmenge ungültig ist.

    | | `invalidProductId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Produkt-ID ungültig ist.

    | | `invalidVariantId` | string | Fehlermeldung, die ausgegeben wird, wenn die gewählte Variante ungültig oder nicht verfügbar ist.

    | | `insufficientAmount` | string | Fehlermeldung, die ausgegeben wird, wenn nicht genügend Bestand für die gewünschte Menge vorhanden ist.

    | | `quantityExceeded` | string | Fehlermeldung, die ausgegeben wird, wenn eine definierte maximale Bestellmenge überschritten wird.

    | | `childProductOnly` | string | Fehlermeldung, die ausgegeben wird, wenn versucht wird, ein Produkt direkt zu bestellen, das nur als "Child"-Produkt konfigurierbar ist.

    | | `itemNotChangeable` | string | Fehlermeldung, die ausgegeben wird, wenn die betreffende Warenkorbposition grundsätzlich nicht geändert werden darf.

    | | `internalError` | string | Fehlermeldung, die ausgegeben wird, wenn ein unerwarteter Systemfehler auftritt.

    | | `invalidChildItem` | string | Fehlermeldung, die ausgegeben wird, wenn eine ungültige Variante referenziert wird.

    | | `expressCheckoutNotAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn der Artikel im Express-Checkout nicht in den Warenkorb gelegt werden darf.

    | | `noVariantFound` | string | Fehlermeldung, die ausgegeben wird, wenn zu den gewählten Optionen keine passende Produktvarianten gefunden wird.

    | ## `actions.checkout*` - Bestellablauf ### `actions.checkoutAccountTypeSelect` - Kontotyp auswählen Auswahl zwischen Gastbestellung, Bestandskunde und Neukunden zum Starten der Bestellung im Checkout gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingAccountType": "", "invalidAccountType": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | -------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingAccountType` | string | Fehlermeldung, die ausgegeben wird, wenn kein Kontotyp ausgewählt wurde.

    | | `invalidAccountType` | string | Fehlermeldung, die ausgegeben wird, wenn ein ungültiger oder im Shop nicht unterstützter Kontotyp übermittelt wurde.

    | ### `actions.checkoutBillAddressSelect` - Rechnungsadresse wählen Mithilfe der Aktion `checkoutBillAddressSelect` werden die Fehlermeldungen bei der Auswahl der Rechnungsadresse im Checkout gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingAddressId": "", "invalidAddressId": "", "invalidBillAddress": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | -------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingAddressId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Adress-ID übermittelt wurde.

    | | `invalidAddressId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Adress-ID ungültig ist oder die Adresse nicht gefunden werden konnte.

    | | `invalidBillAddress` | string | Fehlermeldung, die ausgegeben wird, wenn die Adresse nicht als Rechnungsadresse verwendet werden darf.

    | ### `actions.checkoutConfirm` - Bestellung abschließen Mithilfe der Aktion `checkoutConfirm` werden Fehlermeldungen und E-Mails für den Bestellabschluss gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "customerEmail": { "template": "order_confirmation_customer.htm", "subject": "Ihre Bestellung bei Mein Onlineshop", "fromAddress": "noreply@meinshop.de", "fromName": "Mein Onlineshop", "merchantEmail": "bestellungen@meinshop.de", "attachments": [ { "name": "AGB.pdf", "file": "/files/agb.pdf" } ] }, "paymentFailedEmail": { "template": "order_payment_failed.htm", "subject": "Zahlung Ihrer Bestellung fehlgeschlagen", "fromAddress": "noreply@meinshop.de", "fromName": "Mein Onlineshop", "merchantEmail": "zahlung@meinshop.de" }, "errorCodes": { "accountNotVerified": "", "invalid": "", "productsNotAvailableForOrder": "", "requiredCheckboxUnchecked": "", "requiredTextfieldEmpty": "", "itemsExpired": "", "expiredReservation": "", "guestAccountsDisabled": "", "inExpressCheckout": "", "paymentBlocked": "", "captchaFailed": "", "clearingFailed": "", "orderCreationFailed": "", "checkoutCompletedError": "", "simulateFailedPayment": "", "noPermission": "", "personalLimitExceeded": "", "paymentLimitExceeded": "", "basketNotVerified": "", "voucherGenerateError": "", "invalidVoucherId": "", "voucherDeactivated": "", "voucherExpired": "", "voucherNotYetValid": "", "voucherValueSpent": "", "voucherInsuffientAmount": "", "voucherCurrencyMismatch": "", "voucherInvalidCustomer": "", "voucherInvalidSubshop": "", "voucherIneffective": "", "voucherRepoUpdateFailed": "", "voucherInvalidVoucherConfiguration": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------------------------ | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `customerEmail` | object | Konfiguriert die Bestellbestätigungs-Email an den Kunden (inkl. optionaler Kopie an den Händler und Anhängen).
    Betreff, Absender und Template werden über die allgemeinen E-Mail-Parameter gesteuert, siehe hier: [E-Mail Einstellungen](/konfiguration/e-mails-e-mail-einstellungen) | | `customerEmail.attachments` | array (object) | Liste von Dateianhängen, die der Bestellbestätigungs-E-Mail beigefügt werden (beispielsweise AGB als PDF). Je Anhang sind `name` (angezeigter Dateiname) und `file` (Pfad zur Datei im Shop) anzugeben. Siehe auch [E-Mail Einstellungen](/konfiguration/e-mails-e-mail-einstellungen). | | `paymentFailedEmail` | object | Konfiguriert die E-Mail, die bei fehlgeschlagener Zahlung versendet werden kann.
    Betreff, Absender und Template werden über die allgemeinen E-Mail-Parameter gesteuert, siehe hier: [E-Mail Einstellungen](/konfiguration/e-mails-e-mail-einstellungen) | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `accountNotVerified` | string | Fehlermeldung, die ausgegeben wird, wenn das Kundenkonto noch nicht verifiziert wurde.

    | | `invalid` | string | Fehlermeldung, die ausgegeben wird, wenn die Bestellung nicht bestätigt werden kann.

    | | `productsNotAvailableForOrder` | string | Fehlermeldung, die ausgegeben wird, wenn mindestens ein Artikel im Warenkorb nicht (mehr) bestellbar ist.

    | | `requiredCheckboxUnchecked` | string | Fehlermeldung, die ausgegeben wird, wenn eine erforderliche Checkbox nicht aktiviert wurde.

    | | `requiredTextfieldEmpty` | string | Fehlermeldung, die ausgegeben wird, wenn ein als Pflichtfeld markiertes Eingabefeld leer ist.

    | | `itemsExpired` | string | Fehlermeldung, die ausgegeben wird, wenn der Artikel im Warenkorb inzwischen nicht mehr verfügbar ist.

    | | `expiredReservation` | string | Fehlermeldung, die ausgegeben wird, wenn eine zuvor angelegte Warenkorbreservierung abgelaufen ist.

    | | `guestAccountsDisabled` | string | Fehlermeldung, die ausgegeben wird, wenn Gastbestellungen deaktiviert sind und ein Kunde ohne Konto bestellen möchte.

    | | `inExpressCheckout` | string | Fehlermeldung, die ausgegeben wird, wenn der reguläre Bestellabschluss während eines laufenden Express-Checkouts nicht zulässig ist.

    | | `paymentBlocked` | string | Fehlermeldung, die ausgegeben wird, wenn die Zahlung aufgrund einer Sperre (beispielsweise IP- oder Session-Sperre) blockiert ist.

    | | `captchaFailed` | string | Fehlermeldung, die ausgegeben wird, wenn die Captcha-Prüfung beim Bestellabschluss fehlschlägt.

    | | `clearingFailed` | string | Fehlermeldung, die ausgegeben wird, wenn die Zahlungsfreigabe durch den Zahlungsdienstleister fehlschlägt.

    | | `orderCreationFailed` | string | Fehlermeldung, die ausgegeben wird, wenn die Bestellung technisch nicht angelegt werden konnte.

    | | `checkoutCompletedError` | string | Fehlermeldung, die ausgegeben wird, wenn der Checkout bereits abgeschlossen wurde und nicht erneut ausgeführt werden kann.

    | | `simulateFailedPayment` | string | Fehlermeldung, die ausgegeben wird, wenn im Testmodus eine fehlgeschlagene Zahlung simuliert wird.

    | | `noPermission` | string | Fehlermeldung, die ausgegeben wird, wenn das (Unter-)Konto keine Berechtigung zum Auslösen von Bestellungen hat.

    | | `personalLimitExceeded` | string | Fehlermeldung, die ausgegeben wird, wenn das persönliche Zahlungslimit pro Bestellung überschritten würde.

    | | `paymentLimitExceeded` | string | Fehlermeldung, die ausgegeben wird, wenn das für das Konto hinterlegte Gesamt-Zahlungslimit durch die Bestellung überschritten würde.

    | | `basketNotVerified` | string | Fehlermeldung, die ausgegeben wird, wenn der Warenkorb (im B2B-Kontext) noch nicht freigegeben/verifiziert wurde und deshalb nicht bestellt werden kann.

    | | `voucherGenerateError` | string | Fehlermeldung, die ausgegeben wird, wenn beim Erzeugen eines Gutscheins ein Fehler auftritt.

    | | `invalidVoucherId` | string | Fehlermeldung, die ausgegeben wird, wenn der eingegebene Gutschein-Code nicht existiert oder nicht erkannt wird.

    | | `voucherDeactivated` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutschein deaktiviert ist und nicht mehr eingelöst werden kann.

    | | `voucherExpired` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutschein abgelaufen ist.

    | | `voucherNotYetValid` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutschein erst ab einem späteren Zeitpunkt gültig ist.

    | | `voucherValueSpent` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutschein bereits vollständig verbraucht wurde.

    | | `voucherInsuffientAmount` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutscheinbetrag für diese Bestellung nicht ausreicht.

    | | `voucherCurrencyMismatch` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutschein für eine andere Währung ausgestellt wurde, als im aktuellen Warenkorb verwendet wird.

    | | `voucherInvalidCustomer` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutschein an einen andere Kunden gebunden ist.

    | | `voucherInvalidSubshop` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutschein im aktuellen Subshop nicht gültig ist.

    | | `voucherIneffective` | string | Fehlermeldung, die ausgegeben wird, wenn ein hinterlegter Gutschein für diese Bestellung wirkungslos ist und die Bestellung dadurch blockiert wird.

    | | `voucherRepoUpdateFailed` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutschein-Status beim Einlösen technisch nicht aktualisiert werden konnte.

    | | `voucherInvalidVoucherConfiguration` | string | Fehlermeldung, die ausgegeben wird, wenn die Konfiguration des Gutscheins ungültig ist.

    | ### `actions.checkoutPaymentUpdate` - Zahlungsart ändern Mithilfe der Aktion `checkoutPaymentUpdate` werden die Fehlermeldungen beim Ändern der Zahlungsart im Checkout gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingPaymentId": "", "inactivePayment": "", "invalidPaymentId": "", "expressCheckoutNotAllowed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingPaymentId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Zahlungsart ausgewählt wurde.

    | | `inactivePayment` | string | Fehlermeldung, die ausgegeben wird, wenn die ausgewählte Zahlungsart im Shop deaktiviert ist.

    | | `invalidPaymentId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Zahlungs-ID ungültig ist oder die Zahlungsart nicht gefunden wurde.

    | | `expressCheckoutNotAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn die Änderung der Zahlungsart im Express-Checkout nicht zulässig ist.

    | ### `actions.checkoutPseudoCCSelect` - Kreditkarte wählen Mithilfe der Aktion `checkoutPseudoCCSelect` werden die Fehlermeldungen beim Auswählen einer gespeicherten Kreditkarte im Checkout gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "notLoggedIn": "", "missingPseudoId": "", "notAllowed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ----------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `notLoggedIn` | string | Fehlermeldung, die ausgegeben wird, wenn ein nicht angemeldeter Benutzer versucht, eine gespeicherte Kreditkarte zu verwenden.

    | | `missingPseudoId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Karten-Referenz (Pseudo-ID) übermittelt wurde.

    | | `notAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn die ausgewählte Kreditkarte im aktuellen Kontext nicht verwendet werden darf.

    | ### `actions.checkoutSetFreeFields` - Freitextfelder im Checkout Mithilfe der Aktion `checkoutSetFreeFields` werden die Fehlermeldungen für die Prüfung von Freitextfeldern im Checkout gesteuert. #### Beispielkonfiguration `actions.checkoutSetFreeFields` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "textfieldCheckFailed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `textfieldCheckFailed` | string | Fehlermeldung, die ausgegeben wird, wenn die Validierung eines oder mehrerer Freitextfelder fehlschlägt. (beispielsweise Pflichtfeld leer)

    | ### `actions.checkoutSetGuestEmail` - Gastbestellung Mithilfe der Aktion `checkoutSetGuestEmail` werden die Fehlermeldungen bei der Eingabe der E-Mail-Adresse für eine Gastbestellung gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingGuestEmail": "", "invalidGuestEmail": "", "guestEmailAlreadyUsed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ----------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingGuestEmail` | string | Fehlermeldung, die ausgegeben wird, wenn keine E-Mail-Adresse eingegeben wurde.

    | | `invalidGuestEmail` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene E-Mail-Adresse das erwartete Format nicht erfüllt.

    | | `guestEmailAlreadyUsed` | string | Fehlermeldung, die ausgegeben wird, wenn die E-Mail-Adresse bereits einem registrierten Kundenkonto zugeordnet ist.

    | ### `actions.checkoutShippingAddressSelect` - Lieferadresse wählen Mithilfe der Aktion `checkoutShippingAddressSelect` werden die Fehlermeldungen bei der Auswahl der Lieferadresse im Checkout gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingAddressId": "", "invalidAddressId": "", "expressCheckoutNotAllowed": "", "invalidShippingAddress": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingAddressId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Adress-ID übermittelt wurde.

    | | `invalidAddressId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Adress-ID ungültig ist oder die Adresse nicht gefunden werden kann.

    | | `expressCheckoutNotAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn die Auswahl/Änderung der Lieferadresse im Express-Checkout nicht zulässig ist.

    | | `invalidShippingAddress` | string | Fehlermeldung, die ausgegeben wird, wenn die gewählte Adresse nicht als Lieferadresse verwendet werden darf.

    | ### `actions.checkoutShippingMethodUpdate` - Versandart wählen / ändern Mithilfe der Aktion `checkoutShippingMethodUpdate` werden die Fehlermeldungen beim Ändern der Versandart im Checkout gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingShippingMethodId": "", "inactiveShippingMethodId": "", "invalidShippingMethodId": "", "reservationFailed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | -------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingShippingMethodId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Versandart ausgewählt bzw. keine Versandart-ID übermittelt wurde.

    | | `inactiveShippingMethodId` | string | Fehlermeldung, die ausgegeben wird, wenn die ausgewählte Versandart im Shop deaktiviert oder vorübergehend nicht verfügbar ist.

    | | `invalidShippingMethodId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Versandart-ID ungültig ist oder die Versandart nicht gefunden werden kann.

    | | `reservationFailed` | string | Fehlermeldung, die ausgegeben wird, wenn eine notwendige Reservierung für die Versandart fehlschlägt.

    | ## `actions.guestRegister` - Anmeldung nach Gastbestellung Mithilfe der Aktion `guestRegister` werden die Fehlermeldungen und E-Mails beim Anlegen eines vollwertigen Kundenkontos aus einer Gastbestellung gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "verifyEmail": { "template": "guest_register_verify.htm", "subject": "Bitte bestätigen Sie Ihre Registrierung", "fromAddress": "noreply@meinshop.de", "fromName": "Mein Onlineshop" }, "errorCodes": { "nonGuestAccount": "", "duplicateEmail": "", "missingEmail": "", "missingPassword": "", "passwordMismatch": "", "passwordCheckFailed": "", "createError": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `verifyEmail` | object | Konfiguriert die E-Mail, mit der der ehemalige Gastkunde seine Registrierung bzw. E-Mail-Adresse bestätigen kann.
    Betreff, Absender und Template werden über die allgemeinen E-Mail-Parameter gesteuert, siehe hier: [E-Mail Einstellungen](/konfiguration/e-mails-e-mail-einstellungen) | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `nonGuestAccount` | string | Fehlermeldung, die ausgegeben wird, wenn versucht wird, ein Konto zu registrieren, das kein Gastkonto ist.

    | | `duplicateEmail` | string | Fehlermeldung, die ausgegeben wird, wenn unter der angegebenen E-Mail-Adresse bereits ein Kundenkonto existiert.

    | | `missingEmail` | string | Fehlermeldung, die ausgegeben wird, wenn keine E-Mail-Adresse übermittelt wird.

    | | `missingPassword` | string | Fehlermeldung, die ausgegeben wird, wenn kein Passwort für das neue Kundenkonto angegeben wurde.

    | | `passwordMismatch` | string | Fehlermeldung, die ausgegeben wird, wenn Passwort und Passwortbestätigung nicht übereinstimmen.

    | | `passwordCheckFailed` | string | Fehlermeldung, die ausgegeben wird, wenn das gewählte Passwort die Passwortregeln nicht erfüllt.

    | | `createError` | string | Fehlermeldung, die ausgegeben wird, wenn das Kundenkonto technisch nicht angelegt werden konnte.

    | ### `actions.directOrder` - Direktbestellung Mithilfe der Aktion `directOrder` werden die Fehlermeldungen für Direktbestellungen per Artikelnummer gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "invalidId": "", "missingId": "", "invalidQuantity": "", "missingQuantity": "", "productHasNoVariants": "", "variantDoesNotExist": "", "baseProductCanNotBeChosen": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `invalidId` | string | Fehlermeldung, die ausgegeben wird, wenn die eingegebene Artikel-/Bestellnummer ungültig ist oder kein passender Artikel gefunden wird.

    | | `missingId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Artikel-/Bestellnummer eingegeben wurde.

    | | `invalidQuantity` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Menge ungültig ist.

    | | `missingQuantity` | string | Fehlermeldung, die ausgegeben wird, wenn keine Bestellmenge angegeben wurde.

    | | `productHasNoVariants` | string | Fehlermeldung, die ausgegeben wird, wenn für den gewählten Artikel keine Varianten vorhanden sind, aber eine Variante erwartet wurde.

    | | `variantDoesNotExist` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Variante nicht existiert.

    | | `baseProductCanNotBeChosen` | string | Fehlermeldung, die ausgegeben wird, wenn das Basisprodukt nicht direkt gewählt werden kann und stattdessen eine Variante ausgewählt werden muss.

    | ## `actions.voucher*` - Gutschein ### `actions.voucherAdd` - Gutschein einlösen / hinzufügen Mithilfe der Aktion `voucherAdd` werden die Fehlermeldungen beim Hinzufügen eines Gutscheins zum Warenkorb gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingId": "", "duplicateId": "", "invalidVoucherId": "", "deactivated": "", "expired": "", "notYetValid": "", "maxCountExceeded": "", "valueSpent": "", "insuffientAmount": "", "currencyMismatch": "", "invalidCustomer": "", "invalidSubshop": "", "repoUpdateFailed": "", "invalidVoucherConfiguration": "", "insufficientMinOrderValue": "", "expressCheckoutNotAllowed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ----------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingId` | string | Fehlermeldung, die ausgegeben wird, wenn kein Gutscheincode eingegeben wurde.

    | | `duplicateId` | string | Fehlermeldung, die ausgegeben wird, wenn derselbe Gutscheincode bereits im Warenkorb hinterlegt ist.

    | | `invalidVoucherId` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutscheincode ungültig ist oder kein Gutschein gefunden werden kann.

    | | `deactivated` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutschein im System deaktiviert wurde.

    | | `expired` | string | Fehlermeldung, die ausgegeben wird, wenn die Gültigkeitsdauer des Gutscheins abgelaufen ist.

    | | `notYetValid` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutschein erst ab einem späteren Zeitpunkt gültig ist.

    | | `maxCountExceeded` | string | Fehlermeldung, die ausgegeben wird, wenn die maximale Anzahl an zulässigen Einlösungen überschritten wurde.

    | | `valueSpent` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutschein bereits vollständig eingelöst wurde und kein Restwert mehr vorhanden ist.

    | | `insuffientAmount` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutscheinwert für die aktuelle Bestellung nicht ausreicht.

    | | `currencyMismatch` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutschein für eine andere Währung ausgestellt wurde als im aktuellen Warenkorb verwendet wird.

    | | `invalidCustomer` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutschein an einen anderen Kunden gebunden ist als den aktuell eingeloggten.

    | | `invalidSubshop` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutschein im aktuellen Subshop/Shop nicht eingelöst werden darf.

    | | `repoUpdateFailed` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutschein-Status beim Einlösen technisch nicht aktualisiert werden konnte.

    | | `invalidVoucherConfiguration` | string | Fehlermeldung, die ausgegeben wird, wenn die Konfiguration des Gutscheins ungültig ist.

    | | `insufficientMinOrderValue` | string | Fehlermeldung, die ausgegeben wird, wenn der Mindestbestellwert für die Einlösung des Gutscheins nicht erreicht wird.

    | | `expressCheckoutNotAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn das Einlösen eines Gutscheins im Express-Checkout nicht zulässig ist.

    | ### `actions.voucherDelete` - Gutschein löschen Mithilfe der Aktion `voucherDelete` werden die Fehlermeldungen beim Entfernen eines Gutscheins aus dem Warenkorb gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "invalidVoucherId": "", "expressCheckoutNotAllowed": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `invalidVoucherId` | string | Fehlermeldung, die ausgegeben wird, wenn der angegebene Gutschein im Warenkorb nicht gefunden oder nicht zugeordnet werden kann.

    | | `expressCheckoutNotAllowed` | string | Fehlermeldung, die ausgegeben wird, wenn das Entfernen eines Gutscheins im Express-Checkout nicht zulässig ist.

    | ## `actions.inventoryReserve` - Reservierung im Warenkorb Mithilfe der Aktion `inventoryReserve` werden die Fehlermeldungen beim Reservieren von Lagerbestand für Warenkorbpositionen gesteuert. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "missingBasketItemId": "", "invalidBasketItemId": "", "noReservationFound": "", "insufficientAmount": "", "inventoryInactive": "", "setChildReserveActionInvalid": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorCodes` | object | Konfiguriert die Fehlercodes, die bei Problemen während der Aktion verwendet werden. | | `missingBasketItemId` | string | Fehlermeldung, die ausgegeben wird, wenn keine Warenkorbpositions-ID übermittelt wurde.

    | | `invalidBasketItemId` | string | Fehlermeldung, die ausgegeben wird, wenn die angegebene Warenkorbposition ungültig ist oder nicht gefunden werden kann.

    | | `noReservationFound` | string | Fehlermeldung, die ausgegeben wird, wenn keine passende Reservierung gefunden oder erzeugt werden kann.

    | | `insufficientAmount` | string | Fehlermeldung, die ausgegeben wird, wenn für die gewünschte Menge nicht genügend Bestand verfügbar ist.

    | | `inventoryInactive` | string | Fehlermeldung, die ausgegeben wird, wenn die Bestandsverwaltung bzw. Reservierungsfunktion im System deaktiviert ist.

    | | `setChildReserveActionInvalid` | string | Fehlermeldung, die ausgegeben wird, wenn für eine Set-/Kind-Position keine Reservierung in der angefragten Form zulässig ist.

    | # Admin Interface Source: https://dokumentation.websale.de/admin-interface Das Admin Interface ist das zentrale Backend des WEBSALE-Shops: kaufmännische, organisatorische und technische Verwaltung von Daten und Modulen. Das Admin Interface ist das zentrale Backend der WEBSALE E-Commerce Plattform. Über diese Oberfläche verwalten Sie sämtliche kaufmännischen, organisatorischen und technischen Aspekte Ihres Shops. **Sie erreichen das Admin Interface unter** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin ``` ## Überblick über die Hauptbereiche im Admin Interface * **Dashboard**\ Übersicht über die wichtigsten Kennzahlen, aktuelle Systemmeldungen und den Posteingang offener Anfragen. Enthält Schnellzugriffe auf zentrale Funktionen. * **Katalog**\ Verwaltung Ihrer Produkte und Kategorien. * **Bestellungen**\ Übersicht und Bearbeitung eingegangener Kundenbestellungen. * **Kundendaten**\ Einblick in Kundendatensätze, Aktivitäten und Segmentierungen. * **Anfragen**\ Zentraler Posteingang für alle Nachrichten, die über Shop-Formulare wie Kontaktformular, Rückrufservice oder Reklamation eingehen. * **Templates**\ Verwaltung der Templatekompilierung, Bildkonvertierung und des Key-Value-Stores. * **SEO**\ Pflege von SEO-URLs, SEO-Metadaten, Sitemaps und Datenfeeds. * **Marketing**\ Versand und Verwaltung von E-Mail- und Push-Nachrichten, Produktbewertungen, Gutscheinen und Newsletter-Abonnements. * **Reports & Statistiken**\ Auswertungen zu Shop-Leistung, Fehlerprotokollen und Nutzeraktivitäten. Inklusive Monitoring und Zugriff auf den Log-Manager. * **Einstellungen**\ Grundlegende Konfiguration Ihres Shops, wie Währungen, Steuersätze, Sprachen, Benutzer- und Rollenverwaltung. * **Profil**\ Persönlicher Bereich für den eingeloggten Nutzer – inklusive Berechtigungen und Kontoeinstellungen. ### Hinweis zur Dokumentation Die ausführliche Dokumentation zum Admin Interface wird aktuell noch überarbeitet und steht in Kürze vollständig zur Verfügung. Sollten Sie Fragen zur Bedienung des Admin Interface haben, bestimmte Funktionen nicht finden oder Unterstützung benötigen, steht Ihnen unser Support-Team gerne zur Verfügung. # Kaufgutschein-Produkt anlegen Source: https://dokumentation.websale.de/admin-interface/katalog/produkte/kaufgutschein-produkt Kaufgutschein-Produkte erzeugen: Gutschein-Charge und PDF-Template am Produkt hinterlegen sowie Zahlungsarten, Versandart und Produkttyp richtig setzen. Ein Kaufgutschein ist ein Produkt im Katalog, das der Kunde wie jeden anderen Artikel bestellt und bezahlt. Nach Abschluss der Bestellung generiert der Shop für jede bestellte Einheit einen Gutscheincode und stellt diesen als PDF bereit. Das Produkt allein genügt dafür nicht. Es verweist auf eine Kaufgutscheinvorlage, die zuvor unter angelegt werden muss. Wie das geht, ist unter [Gutscheine](/admin-interface/marketing/gutscheine#kaufgutscheinvorlage-anlegen) beschrieben. Diese Seite setzt voraus, dass die Vorlage existiert und ihre Chargen-ID bekannt ist. *** ## Die Gutscheinfelder am Produkt Ein Kaufgutschein-Produkt wird über folgende Felder gesteuert. Diese befinden sich in der Produktmaske im Abschnitt "Allgemeine Felder": | Feld in der Produktmaske | Wirkung | Technischer Name | | -------------------------------------- | -------------------------------------------------- | ---------------------------- | | Kaufgutschein | Kennzeichnet das Produkt als Kaufgutschein-Produkt | `voucherProductActive` | | Gutschein-Charge | Chargen-ID der Kaufgutscheinvorlage | `voucherProductCharge` | | HTML-Template | Pfad des View-Templates für das Gutschein-PDF | `voucherProductHtmlTemplate` | | Produktpreis entspricht Gutschein-Wert | Setzt den Gutscheinwert auf den Positionspreis | `voucherProductPrice` | *** ## Das Kaufgutschein-Produkt anlegen Angelegt wird das Produkt im Admin-Interface unter über "+ Neues Produkt". Zuerst die üblichen Angaben im Abschnitt Allgemeine Felder: | Feld | Hinweis | | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Produktname | Der Name, unter dem der Gutschein im Shop verkauft wird | | Produkt-ID und Produktnummer | Wie bei jedem anderen Produkt | | Preis | Der Verkaufspreis, und je nach Einstellung zugleich der Wert des erzeugten Gutscheins, siehe [Den Wert des Gutscheins festlegen](#den-wert-des-gutscheins-festlegen) | | Mehrwertsteuer | Pflichtangabe | | Produkttyp | Nur nötig, wenn eine Versandart auf den Produkttyp prüft. Dann der Typ, den deren Regelliste erwartet, siehe [Versandart und Produkttyp](#versandart-und-produkttyp) | | Status | Auf "Aktiv" setzen, damit das Produkt im Shop erscheint | Weiter unten im selben Abschnitt stehen die Gutscheinfelder: Doku Kaufgutschein Produktfelder | Feld | Wert | | ------------------------------------------ | --------------------------------------------------------------------------------------------------------- | | **Kaufgutschein** | einschalten | | **Gutschein-Charge** | Chargen-ID der Kaufgutscheinvorlage, beispielsweise `geschenkgutschein` | | **HTML-Template** | Pfad des View-Templates, beispielsweise `voucher/default_voucher.htm` | | **Produktpreis entspricht Gutschein-Wert** | einschalten, wenn der Gutscheinwert dem Produktpreis folgen soll | | **Zulässig für Wertgutscheine** | betrifft das Einlösen von Werbegutscheinen auf dieses Produkt und hat mit dem Kaufgutschein nichts zu tun | In das Feld "Gutschein-Charge" gehört die **Chargen-ID**, nicht die Bezeichnung der Vorlage. Der Shop sucht die Kaufgutscheinvorlage ausschließlich über diese ID. Eine Vorlagen-ID oder ein Anzeigename führt beim Bezahlen zum Abbruch. *** ## Den Wert des Gutscheins festlegen Der Wert eines gekauften Gutscheins kann aus zwei Quellen kommen. Welche gilt, entscheidet der Schalter "Produktpreis entspricht Gutschein-Wert" am Produkt. | Schalter | Woher der Wert kommt | Wann das passt | | ------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | eingeschaltet | Aus dem Preis der Warenkorbposition | Der Regelfall. Eine Kaufgutscheinvorlage genügt für beliebig viele Wertstufen, weil jedes Produkt seinen Wert über den Preis mitbringt | | ausgeschaltet | Aus dem Gutscheinwert der Kaufgutscheinvorlage | Nur sinnvoll, wenn alle Gutscheine denselben festen Wert haben. Für jede weitere Wertstufe braucht es dann eine eigene Vorlage mit eigener Charge | ### Dem Kunden mehrere Wertstufen anbieten Für einen frei eingetippten Betrag gibt es keine Funktion. Der Kunde wählt immer aus fest angelegten Wertstufen, und dafür gibt es zwei Wege: | Weg | Aufbau | Wirkung im Shop | | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Ein Produkt je Wertstufe** | Beispielsweise drei Produkte "Geschenkgutschein 25", "50" und "100", jedes mit seinem Preis. Alle drei tragen dieselbe Chargen-ID. | Drei eigenständige Produkte mit eigenen Produktseiten, eigenen Bildern und eigenen SEO-URLs | | **Ein Produkt mit Varianten** | Ein Produkt "Geschenkgutschein" mit einer Varianteneigenschaft, beispielsweise "Wert", und je Wertstufe eine Variante mit abweichendem Preis. | Eine Produktseite, auf der der Kunde den Wert wie eine Größe oder Farbe auswählt. Maßgeblich ist der Preis der Warenkorbposition, also der Preis der gewählten Variante. Wie Varianten angelegt werden, beschreibt [Varianten](/varianten). | Beide Wege kommen mit einer einzelnen Kaufgutscheinvorlage aus, solange "Produktpreis entspricht Gutschein-Wert" eingeschaltet ist. *** ## Zahlungsarten und Versandarten Weil ein gekaufter Gutschein sofort einlösbar ist, greifen im Bestellablauf Einschränkungen, die gesetzt werden müssen. ### Zahlungsarten Ein Gutschein ist sofort einlösbar, das Geld dafür ist bei einer Zahlungsart mit Zahlungsziel aber noch nicht eingegangen. Um dieses Risiko auszuschließen, gibt es den Prüfservice [`paymentValidation.voucherDeny`](/konfiguration/validierungs-und-prufservices). Er sperrt eine Zahlungsart, sobald ein Gutscheinprodukt im Warenkorb liegt. Eingetragen wird er nicht zentral, sondern je Zahlungsart in deren Liste `validations` unter [`payment.payment`](/konfiguration/payment-zahlungsmethoden). Sinnvoll ist der Eintrag bei allen Zahlungsarten mit Zahlungsziel, typischerweise Rechnung, Vorkasse, Nachnahme und Lastschrift. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "service": "paymentValidation.voucherDeny" } ] ``` Ohne diesen Eintrag bleiben alle Zahlungsarten wählbar, auch mit einem Gutschein im Warenkorb. Die Prüfservices selbst tragen keine Werte, sie werden nur referenziert. Wer die Sperre auf der Seite der Prüfservices sucht, findet dort nichts. Greift der Service, wirkt er auf die gesamte Bestellung und nicht nur auf die Gutscheinposition. Liegt ein Gutscheinprodukt neben regulären Artikeln im Warenkorb, ist die Zahlungsart für den ganzen Warenkorb gesperrt. ### Versandart und Produkttyp Ein Warenkorb, der nur Gutscheine enthält, braucht keinen physischen Versand. Dafür wird eine eigene, immer kostenfreie Versandart angelegt und über den Prüfservice [`shippingMethodValidation.productType`](/konfiguration/validierungs-und-prufservices) auf Gutscheinprodukte beschränkt. Auch dieser Eintrag steht je Versandart in deren Liste `validations` unter [`checkout.shippingMethod`](/konfiguration/checkout-bestellablauf#checkout-shippingmethod-versandarten). Das vollständige Beispiel mit Preisstaffel und Regelliste steht in den [Praxisbeispielen Gutscheine](/gutscheine). Die Regel entscheidet anhand des Produkttyps der Artikel im Warenkorb. Trägt das Kaufgutschein-Produkt nicht den Typ, den die Regelliste erwartet, lehnt die Prüfung die Versandart mit dem Fehler `productTypeDenied` ab, und der Kunde fällt auf eine physische Versandart samt Versandkosten zurück. Das passiert auch dann, wenn das Feld "Produkttyp" am Produkt leer bleibt. *** ## Was beim Bestellabschluss passiert Die Gutscheine entstehen nicht beim Legen in den Warenkorb, sondern beim Abschluss der Bestellung: 1. Der Shop liest die Chargen-ID aus dem Produktfeld und sucht die Kaufgutscheinvorlage mit dieser ID. 2. Er erzeugt je bestellter Einheit einen Gutschein mit den Daten der Vorlage. 3. Ist "Produktpreis entspricht Gutschein-Wert" aktiv, übernimmt er den Positionspreis als Gutscheinwert, andernfalls gilt der Wert aus der Vorlage, siehe [Den Wert des Gutscheins festlegen](#den-wert-des-gutscheins-festlegen). 4. Existiert zu der ID keine Vorlage, behandelt er die Charge als Pool importierter Codes und reserviert daraus. Ist auch das nicht möglich, bricht der Bestellabschluss ab. Die erzeugten Codes und die Links auf die Gutschein-PDFs stehen anschließend in den Bestelldaten unter `data.orderList.item[].voucher`, siehe [API-Referenz Bestellungen](/schnittstellen/admin-interface-api/api-referenz-bestellungen). Solange eine Bestellung nicht abgeschlossen ist, bleiben beide Listen leer. *** ## Anzeige im Shop Wie der Gutschein im Shop erscheint, bestimmt das Template. Im Admin-Interface gibt es dafür keine Einstellungen. * Das im Feld "HTML-Template" hinterlegte View-Template erzeugt das PDF. Grundlagen dazu stehen unter [PDF-Ansichten](/frontend/funktionsubersicht/pdf-ansichten). * Der Download-Link für den Kunden wird auf der Bestellbestätigungsseite und in der Bestellbestätigungs-E-Mail ausgegeben. Ein vollständiges Beispiel steht in den [Praxisbeispielen Gutscheine](/gutscheine). *** ## Typische Fehler | Beobachtung | Ursache | Lösung | | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | Beim Bezahlen erscheint die Meldung, dass der Gutschein nicht erzeugt werden kann | Im Feld "Gutschein-Charge" steht nicht die Chargen-ID der Kaufgutscheinvorlage | Chargen-ID aus dem Reiter Kaufgutscheinvorlage übernehmen | | Dieselbe Meldung, obwohl die ID stimmt | Zu der Charge gehört keine Kaufgutscheinvorlage, sondern eine normale Charge mit fertigen Codes | Vorlage über das Pfeilmenü neu anlegen, siehe [Gutscheine](/admin-interface/marketing/gutscheine#kaufgutscheinvorlage-anlegen) | | Der PDF-Link führt ins Leere | Das hinterlegte View-Template existiert nicht oder wertet die übergebene `voucherId` nicht aus | Template-Pfad prüfen | | Im Bestellablauf erscheint die kostenfreie Versandart für Gutscheine nicht | Der Produkttyp am Produkt fehlt oder passt nicht zur Regelliste der Versandart, die Prüfung meldet `productTypeDenied` | Produkttyp und Regelliste abgleichen, siehe [Versandart und Produkttyp](#versandart-und-produkttyp) | | Eine Zahlungsart fehlt im Bestellablauf | An der Zahlungsart hängt `paymentValidation.voucherDeny`, dann ist das gewollt. Andernfalls greift eine andere Validierung dieser Zahlungsart | Eintrag der Zahlungsart prüfen, siehe [Validierungs- und Prüfservices](/konfiguration/validierungs-und-prufservices) | Die genaue Ursache steht im [Log-Manager](/admin-interface/logmanager-logs). Alle Meldungen der Gutscheinerzeugung beginnen mit `voucherService.`: | Log-Kategorie | Bedeutung | | ------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | `voucherService.vouchersGenerated` | Für eine Position wurden Gutscheine erzeugt oder reserviert | | `voucherService.poolActivationFailed` | Es konnten nicht alle Codes bereitgestellt werden | | `voucherService.invalidVoucherQuantity` | Die Menge der Position ist kleiner oder gleich null | | `voucherService.voucherFlagMismatch` | Die Kennzeichnung als Gutscheinprodukt hat sich zwischen Warenkorb und Bestellabschluss geändert | | `voucherService.generateVoucherProductLoadFailed` | Das Produkt konnte beim Bestellabschluss nicht geladen werden | | `voucherService.activateMissingReservation` | Eine Position wurde als Gutscheinprodukt bestellt, ohne dass eine Reservierung vorliegt | *** ## Wegweiser * [Gutscheine](/admin-interface/marketing/gutscheine) beschreibt das Anlegen der Kaufgutscheinvorlage. * [content - Katalog, Kategorien und Produkte](/konfiguration/content-katalog-kategorien-produkte) beschreibt die benutzerdefinierten Produktfelder und ihre Zuordnung. * [API-Referenz Produkte](/schnittstellen/admin-interface-api/api-referenz-produkte) beschreibt dieselben Felder über die Schnittstelle. * [PDF-Ansichten](/frontend/funktionsubersicht/pdf-ansichten) beschreibt die Erzeugung des Gutschein-PDFs. # Varianten Source: https://dokumentation.websale.de/admin-interface/katalog/produkte/varianten Varianten sind der zentrale Ort, an dem alle Ausführungen gepflegt werden, in denen der Shop seine Produkte anbieten kann. Varianten sind keine eigenständigen Artikel, sondern untergeordnete Versionen eines Hauptprodukts. Sie unterscheiden sich in bestimmten Merkmalen wie Größe, Farbe oder Material. ## Das Grundprinzip Zuerst legen Sie einmalig fest, welche Merkmale es im Shop überhaupt gibt und welche Werte sie annehmen können. Beispielsweise können Sie die Eigenschaft "Größe" mit den Optionen "36", "38" und "40" oder die Eigenschaft "Farbe" mit den Optionen "Grün", "Blau" und "Rot" definieren. Diese Definition gilt shopweit und steht damit allen Produkten zur Verfügung. Sie beschriebt, was es geben darf - nicht, was ein einzelnes Produkt tatsächlich hat. Diese Definition gilt shop-weit und steht damit allen Produkten zur Verfügung. Sie beschreibt, was es geben *darf* – nicht, was ein einzelnes Produkt tatsächlich hat. Bei einem Produkt bestimmen Sie, welche Eigenschaften für dieses Produkt gelten (zum Beispiel Größe und Farbe) und welche Optionen dieser Eigenschaft dafür infrage kommen. Aus den gewählten Optionen entstehen die eigentlichen Varianten. Dafür gibt es zwei Wege: * eine automatische Kombination der gewählten Optionen erzeugen oder  * gezielt und manuell einzelne Kombinationen zusammenstellen. Jede Kombination wird eine Variante mit eigener Varianten-ID und kann eigene Werte tragen wie etwa einen abweichenden Preis. Gepflegt wird beides im Admin Interface unter . Erklärung des Unterschieds zwischen einer Variante und einer Eigenschaft: | Ebene | Was es ist | Gültigkeit | | ------------------------ | ------------------------------------------------------------------------------------------------------------------- | --------------------------- | | **Varianteneigenschaft** | „größe", und darunter die **Optionen** `s`, `m`, `l`. | shopweit, für alle Produkte | | **Variante** | Das Produkt in Größe `m`. Jede Variante hat eine eigene Varianten-ID, einen eigenen Preis und einen eigenen Status. | am einzelnen Produkt | *** ## Varianteneigenschaften shopweit pflegen Die Liste aller Varianteneigenschaften erreichen Sie aus der Variantenliste eines Produkts über das "**⋮-Menü**" oben rechts und den Eintrag "**Varianteneigenschaften verwalten**". Varianten Eigenschaftsverwaltung 1 Die Liste zeigt alle Eigenschaften mit ihren Optionen. Über **"+ Neue Eigenschaft**" kommt eine weitere hinzu, das Suchfeld **"Eigenschaften durchsuchen"** filtert, und der Pfeil am Zeilenanfang klappt die vollständige Optionsliste auf. Das "**⋮-Menü**" einer Zeile führt zu **Eigenschaft bearbeiten** und **Eigenschaft löschen**. Varianten Eigenschaften Bearbeiten ### Eine Eigenschaft anlegen Beim Anlegen geben Sie den Namen der Eigenschaft sowie mindestens eine Option an. Sowohl der Name als auch der Optionswert dürfen bis zu 128 Zeichen lang sein. Der Name wird unverändert übernommen, das heißt Groß- und Kleinkschreibung sowie Leerzeichen bleiben erhalten. Eigenschaften sind voneinander völlig unabhängig. Sie können deshalb ohne Weiteres mehrere Größen-Eigenschaften parallel führen, etwa `größe-schuhe`, `größe-oberteile` und `größe-hemden-damen`. Es gibt keine Begrenzung der Anzahl von Eigenschaften oder Optionen. ### Eine Eigenschaft bearbeiten Im Bearbeitungsdialog können der Name der Eigenschaft und ihre Optionen geändert werden. * Unter "**Allgemeine Einstellungen"** steht der "**Name der Eigenschaft"**. Er ist ein Pflichtfeld. * Unter **"Optionen"** stehen die Optionen. Über **"+ Option hinzufügen"** kommt eine weitere hinzu; das **"⋮-Menü"** einer Zeile bearbeitet oder entfernt sie. * Die Spalte **Reihenfolge** trägt je Zeile die Möglichkeit zum Drag & Drop. Damit sortieren Sie die Optionen. Eigenschaft Bearbeiten Details Benennen Sie eine Eigenschaft auf einen Namen um, der bereits existiert, werden die Optionen dieser Eigenschaften zusammengeführt. ### Die Reihenfolge der Optionen Neue Optionen werden zunächst in der Reihenfolge anngezeigt, in der sie angelegt wurden. Bei Größen führt das schnell zu einer Auswahl wie `xl`, `3xl`, `s`, `m`, `l`, `2xl`. Technisch korrekt, im Shop aber oft unbrauchbar. Per Drag & Drop wird daraus beispielsweise die erwartete Folge `s`, `m`, `l`, `xl`, `2xl`, `3xl`. Die hier festgelegte Reihenfolge gilt shopweit für diese Eigenschaft. In dieser Reihenfolge werden die Optionen im Frontend des Shops zur Auswahl angeboten. ### Eigenschaften und Optionen löschen Beim Löschen einer Eigenschaft werden auch ihre Optionen entfernt. Eine von einer Produktvariante verwendete Eigenschaft oder Option lässt sich nicht löschen. In der Fehlermeldung wird Ihnen das betreffende Produkt genannt. Entfernen Sie zuerst die Varianten, die diese Eigenschaft oder Option nutzen, aus dem betreffenden Produkt. Um eine Option lediglich aus dem Verkauf zu nehmen, ist das Löschen nicht der richtige Weg. Wie das geht, erfahren Sie unter [Varianten aus dem Shop nehmen](#varianten-aus-dem-shop-nehmen). *** ## Varianten einem Produkt zuweisen Am Produkt wählen Sie aus den shopweiten Eigenschaften die Optionen aus, die für dieses Produkt in Frage kommen. Anschließend gibt es zwei Möglichkeiten, zu den gewünschten Kombinationen zu kommen: * **Automatisch:** Es werden alle möglichen Kombinationen aus den Optionen der gewählten Eigenschaften erzeugt. Das ist der schnellste Weg, wenn es das Produkt tatsächlich in allen vorliegenden Kombinationen gibt. * **Manuell:** Stellen Sie die Kombinationen einzeln zusammen, indem Sie für jede Eigenschaft einen Wert auswählen und hinzufügen. Wiederholen Sie den Vorgang für alle Eigenschaften. Bestätigen Sie die Auswahl am Ende über **"Varianten erstellen"**. Dieser Weg ist geeignet, wenn es nur bestimmte Kombinationen gibt, beispielsweise das Hemd in `blau` nur in den Größen `m` und `l , in `weiß aber in allen Größen. Produkt Variante Zuweisen Manuell (Screenshot Stand 24.08.2026) Bereits vorhandene Kombinationen bleiben in beiden Fällen unberührt. Es werden nur die noch nicht vorhandenen angelegt. ### Eigenschaften nachträglich ergänzen Ob ein späteres Ergänzen von Eigenschaften harmlos oder destruktiv ist, hängt davon ab, was Sie ergänzen: * **Weitere Optionen einer bereits genutzten Eigenschaft**, etwa eine weitere Farbe zu einem Produkt ergänzen, das bereits Farben hat, ist unkritisch. Die neuen Kombinationen kommen hinzu, die bestehenden Varianten bleiben erhalten. * **Eine zusätzliche Eigenschaft**, wie beispielsweise `Größe`, die zu einem Produkt hinzugefügt wird, das bisher nur die Eigenschaft `Farbe` hatte, verändert die Struktur des Produkts. Wenn eine Eigenschaft hinzugefügt oder entfernt wird, werden alle bestehenden Varianten des Produkts gelöscht und neu erstellt. Dadurch gehen alle variantenspezifischen Werte wie abweichende Preise, Artikelnummern, Beschreibungen und Lagerbestände verloren. Es ist nicht möglich, eine Eigenschaft hinzuzufügen und dabei die bestehende Varianten zu erhalten. Planen Sie deshalb am Besten von Anfang an, welche Eigenschaften ein Produkt haben soll. ### Optionen gelten immer shop-weit Ein Optionswert, der nur bei einem einzigen Produkt vorkommt, kann nicht am Produkt selbst angelegt werden. Wenn Sie beispielsweise `marineblau` für ein Hemd benötigen, legen Sie die Option in der Eigenschaft `Farbe` an - sie steht damit allen Produkten zur Verfügung. Produktspezifisch ist nur die Auswahl der Optionen, nicht der Wert selbst. *** ## Was sich je Variante unterscheiden darf Eine Variante ist kein eigenständiges Produkt, sondern erbt zunächst alle Eigenschaften des Hauptprodukts. Nur die Felder, die Sie bei der Variante zusätzlich setzen, weichen ab. Alle übrigen entsprechen dem Hauptprodukt. Wenn Sie also den Preis einer Variante setzen, gilt dieser. Wenn Sie den Preis in der Variante leer lassen, gilt der Preis des Hauptprodukts. Damit lässt sich beispielsweise der Fall abbilden, dass die Größe `s` in der Farbe `marineblau` günstiger ist als die Größe `m` in der Farbe `gelb`: Sie tragen den abweichenden Preis an der jeweiligen Variante ein. Welche Felder überhaupt je Variante abweichen dürfen, ist je Produktdatenfeld konfiguriert. Nur Felder mit dieser Kennzeichnung erscheinen im Formular einer Variante. Standardmäßig sind unter anderem die Felder Name, Artikelnummer, Beschreibung, Preis, Steuersatz und Status variantenfähig, die Zeitstempel dagegen nicht. Auch eigene Produktdatenfelder lassen sich so freischalten - siehe [content – Katalog (Kategorien & Produkte)](/konfiguration/content-katalog-kategorien-produkte). Der Lagerbestand dagegen folgt einer eigenen Logik. Jede Variante hat ihren eigenen Bestand, der unabhängig vom Hauptprodukt ist. Wenn eine Variante gelöscht wird, wird auch ihr Bestand gelöscht. ## Varianten aus dem Shop nehmen Wenn eine Variante ausverkauft ist oder aus anderen Gründen nicht mehr im Shop erscheinen soll, gibt es zwei Möglichkeiten: * **Status ändern:** Jede Variante trägt ein Feld **"Status"**. In der Liste wird es als Badge angezeigt, wobei "Aktiv" grün gekennzeichnet ist und "Inaktiv" rot. Eine inaktive Variante wird im Shop nicht angezeigt. Der Vorteil bei dieser vorgehensweise ist, dass die Variante mit all ihren Werten erhalten bleibt und sich später wieder reaktivieren lässt. - **Variante löschen:** Über das **"⋮-Menü"** am Ende der Zeile lässt sich eine Variante löschen. Dabei gilt: Optionen, die danach von keiner Variante des Produkts mehr verwendet werden, verschwinden auch aus den Eigenschaften dieses Produkts. Der Lagerbestand der Variante wird ebenfalls gelöscht. Die Eigenschaften selbst bleiben am Produkt gesetzt, auch wenn Sie die letzte Variante löschen. ## Anzeige im Shop Wie die Varianten im Shop erscheinen, wird durch das Template bestimmt. Im Admin-Interface gibt es dafür keine Einstellungen. Folgende Punkte sind dabei zu beachten: * **Der Name der Eigenschaft** ist der, den Sie eingetragen haben. Ein separates Feld für einen abweichenden Anzeigenamen gibt es nicht. Wenn im Shop `Schuhe` stehen soll, obwohl die Eigenschaft `größe-schuhe` heißt, muss das Template diese Zuordnung vornehmen, zum Beispiel über einen [Textbaustein](/textbausteine). * **Die Darstellungsform** wie zum Beispiel als Auswahlliste, Radiobuttons, Links oder Farbfelder ist ebenfalls Sache des Templates. Es gibt kein Feld, mit dem sich das je Eigenschaft festlegen lässt. Wie ein Template die Eigenschaften und Optionen ausliest und wie es mit Kombinationen umgeht, die es nicht gibt, steht unter [`$wsProducts` – Produktdaten](/frontend/referenz/module/wsproducts). ## Wegweiser * [API-Referenz Produkte](/schnittstellen/admin-interface-api/api-referenz-produkte) – Endpunkte für Variantenattribute und Produktvarianten. * [`$wsProducts` – Produktdaten](/frontend/referenz/module/wsproducts) – Ausgabe der Varianten im Template. * [content – Katalog (Kategorien & Produkte)](/konfiguration/content-katalog-kategorien-produkte) – Produktdatenfelder und ihre Variantenfähigkeit. * [Textbausteine](/textbausteine) – Pflege der Texte, die der Shop anzeigt. # LogManager (Logs) Source: https://dokumentation.websale.de/admin-interface/logmanager-logs LogManager im Admin Interface: Log-Gruppen definieren, Protokolle aus verschiedenen Bereichen sammeln und Meldungen gezielt erfassen und auswerten. Mit dem LogManager lassen sich Protokolle gezielt erfassen, bündeln und auswerten. Dazu können Log-Gruppen definiert werden, in denen festgelegt wird, welche Meldungen aus welchen Bereichen gesammelt werden sollen. *** ## Aufruf des Services Können Sie über folgende URL aufrufen: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://ihr-shop.de/admin/logmanager/ ``` *** ## Allgemein Der Dienst ist nur sichtbar, wenn die dafür erforderliche Berechtigung vorhanden ist. Ist der Dienst nicht sichtbar, wenden Sie sich bitte an Ihren Shop-Administrator. Logs werden im LogManager immer über Log-Gruppen erfasst. In einer Log-Gruppe legen Sie fest, welche Protokolleinträge gesammelt werden sollen. Dabei können Sie Einträge gezielt eingrenzen oder auch Meldungen aus mehreren Bereichen in einer gemeinsamen Gruppe zusammenfassen. Für jede Log-Gruppe müssen eine sprechende Bezeichnung und eine Beschreibung hinterlegt werden. Dadurch lässt sich später leichter nachvollziehen, welche Logs in der jeweiligen Gruppe erfasst werden. Zusätzlich kann für jede Log-Gruppe optional eine E-Mail-Benachrichtigung eingerichtet werden. *** ## Erklärung der Filter ### Log-Kategorie Legt fest, aus welchem fachlichen oder technischen Bereich Protokolleinträge in die Log-Gruppe aufgenommen werden. Zur besseren Verständlichkeit wird die Kategorie mit einer sprechenden Bezeichnung dargestellt werden, ergänzt um den technischen Kategorienamen in Klammern. #### Administration, Konfiguration & System | **Technische Kategorie** | **Sprechende Bezeichnung** | **Beschreibung** | | -------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------- | | `AdminAccountMailer` | Administrations-E-Mails | Protokolliert Vorgänge und Fehler beim Versand systemseitiger E-Mails an Administrationskonten. | | `configUpdater.dispatcher` | Konfigurationsverteilung | Protokolliert die Verteilung und Weitergabe von Konfigurationsänderungen an nachgelagerte Prozesse. | | `configUpdater.main` | Konfigurationsaktualisierung | Protokolliert Vorgänge und Fehler beim Aktualisieren zentraler Systemeinstellungen. | | `main` | Zentrale Anwendung | Protokolliert allgemeine Vorgänge und Fehler der Hauptanwendung, die keinem spezielleren Bereich zugeordnet sind. | | `HealthProbeService` | Systemzustandsprüfung | Protokolliert Prüfungen des Systemzustands und Auffälligkeiten bei Erreichbarkeit oder Betriebsbereitschaft. | | `host.fcgi` | Host-Schnittstelle / FCGI | Protokolliert technische Vorgänge in der Anbindung der Anwendung an die Host- bzw. FCGI-Umgebung. | | `DirectoryManager` | Verzeichnisverwaltung | Protokolliert Vorgänge und Fehler beim Anlegen, Prüfen oder Verwalten von Verzeichnissen. | | `router` | Anwendungs-Router | Protokolliert die technische Weiterleitung und Zuordnung eingehender Anfragen innerhalb der Anwendung. | | `routing.middleware` | Routing-Middleware | Protokolliert vorbereitende und begleitende Verarbeitungsschritte beim Routing von Anfragen. | | `controller.middleware` | Controller-Middleware | Protokolliert allgemeine technische Verarbeitungsschritte vor oder nach der Ausführung von Controllern. | | `ThemeStorage` | Theme-Speicher | Protokolliert Vorgänge und Fehler beim Zugriff auf Themes, Designressourcen oder zugehörige Speicherdaten. | #### App-API & Eingabehilfen | **Technische Kategorie** | **Sprechende Bezeichnung** | **Beschreibung** | | ---------------------------------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `appapi` | App-API | Protokolliert allgemeine Vorgänge und Fehler in der App-API. | | `appapi.controllers.register` | App-API / Registrierung | Protokolliert Vorgänge und Fehler bei Registrierungs- oder Anmeldeprozessen über die App-API. | | `appapi.controllers.register::getConfig` | App-API / App-Konfiguration | Protokolliert das Abrufen der Konfiguration für die App. | | `appapi.controllers.settings` | App-API / Einstellungen | Protokolliert Vorgänge und Fehler beim Lesen oder Verarbeiten von Einstellungen über die App-API. | | `appapi.controllers.v8` | App-API / Version 8 | Protokolliert Vorgänge und Fehler in Endpunkten oder Funktionen der App-API-Version 8. | | `inputAssistant` | Geführte Eingaben und Assistenten | Protokolliert Vorgänge und Fehler in Funktionen, die Eingaben unterstützen oder Benutzer schrittweise durch Eingaben führen. | | `inputassistant.controllers.assistant` | Steuerung der Eingabehilfe | Protokolliert Vorgänge und Fehler in der technischen Steuerung des Eingabeassistenten. | | `inputAssistant.sessioncheck` | Sitzungsprüfung bei Eingabehilfen | Protokolliert die Prüfung, ob Sitzungen im Zusammenhang mit Eingabehilfen gültig und nutzbar sind. | | `inputAssistant.startup` | Start der Eingabehilfe | Protokolliert Initialisierung und Start der Eingabehilfen. | #### Produktdaten, Kategorien und Suche | **Technische Kategorie** | **Sprechende Bezeichnung** | **Beschreibung** | | ---------------------------------------- | -------------------------------- | ---------------------------------------------------------------------------------------------- | | `category-builder` | Kategorieaufbau | Protokolliert Vorgänge und Fehler beim Erstellen oder Anwenden von Regeln zur Kategorisierung. | | `categoryProductsRebuilder` | Neuaufbau von Kategorieprodukten | Protokolliert die Neuberechnung oder Neuaufbereitung von Produktzuordnungen in Kategorien. | | `data.products.repository` | Produktdatenbestand | Protokolliert Zugriffe, Verarbeitung und Fehler im zentralen Produktdatenbestand. | | `data.products.repository.variantloader` | Variantenladeprozess | Protokolliert das Laden und Verarbeiten von Produktvarianten. | | `data.search.productsearch` | Produktsuche | Protokolliert Suchvorgänge und Fehler bei der Produktsuche. | | `shop.viewController.category` | Kategorieansicht im Shop | Protokolliert die Verarbeitung und Ausgabe von Kategorieseiten im Shop. | | `shop.viewController.search` | Suchergebnisse im Shop | Protokolliert die Verarbeitung und Ausgabe von Suchergebnisseiten im Shop. | #### Importe, Exporte und Datenfeeds | **Technische Kategorie** | **Sprechende Bezeichnung** | Beschreibung | | ------------------------ | -------------------------- | ------------------------------------------------------------------------------------------------- | | `importer` | Produktimporte | Protokolliert Vorgänge und Fehler beim Import von Produktdaten. | | `importermiddleware` | Importverarbeitung | Protokolliert technische Zwischenschritte bei der Verarbeitung von Importen. | | `ImportStatusService` | Importstatus | Protokolliert den Ermittlungs- und Bereitstellungsprozess von Importstatusinformationen. | | `DatafeedBuilder` | Datenfeed-Erstellung | Protokolliert Vorgänge und Fehler bei der Erstellung von Datenfeeds. | | `feedBuilder.startup` | Start der Feed-Erstellung | Protokolliert Initialisierung und Start der Feed-Erzeugung. | | `feedbuildermiddleware` | Feed-Verarbeitung | Protokolliert technische Verarbeitungsschritte im Zusammenhang mit der Erstellung von Datenfeeds. | | `reporter` | Reporting | Protokolliert Vorgänge und Fehler bei der Erstellung oder Verarbeitung von Reports. | | `reportStatusService` | Reportstatus | Protokolliert die Ermittlung und Bereitstellung von Statusinformationen zu Reports. | #### Bilder, Videos und Medienverarbeitung | **Technische Kategorie** | **Sprechende Bezeichnung** | **Beschreibung** | | -------------------------- | -------------------------------- | --------------------------------------------------------------------------------------------- | | `imageChecker` | Bildprüfung | Protokolliert Prüfungen und Fehler bei der Kontrolle von Bilddateien. | | `imageConverter` | Bildkonvertierung | Protokolliert Vorgänge und Fehler bei der Umwandlung von Bilddateien. | | `imageconvertermiddleware` | Bildkonvertierung / Verarbeitung | Protokolliert technische Zwischenschritte bei der Verarbeitung von Bildkonvertierungen. | | `imageconverterstatus` | Bildkonvertierung / Status | Protokolliert Statusinformationen zu laufenden oder abgeschlossenen Bildkonvertierungen. | | `html2mime` | HTML-zu-MIME-Verarbeitung | Protokolliert die Umwandlung von HTML-Inhalten in MIME-kompatible Formate, z. B. für E-Mails. | | `html2mime.main` | HTML-zu-MIME / Hauptprozess | Protokolliert den zentralen Ablauf der HTML-zu-MIME-Konvertierung. | | `video_uploader` | Video-Uploads | Protokolliert Vorgänge und Fehler beim Hochladen und Verarbeiten von Videos. | #### E-Mail, Newsletter und Benachrichtigungen | **Technische Kategorie** | **Sprechende Bezeichnung** | **Beschreibung** | | --------------------------- | ----------------------------- | ----------------------------------------------------------------------------------------------- | | `mailbackup` | E-Mail-Archivierung | Protokolliert Vorgänge und Fehler beim Sichern oder Archivieren versendeter E-Mails. | | `mailer` | E-Mail-Versand | Protokolliert allgemeine Vorgänge und Fehler beim Versand von E-Mails. | | `mailer.main` | E-Mail-Versand / Hauptprozess | Protokolliert den zentralen Ablauf des E-Mail-Versands. | | `newsletterSubscribeHelper` | Newsletter-Anmeldung | Protokolliert Vorgänge und Fehler bei der Anmeldung zu Newslettern. | | `notificator` | Benachrichtigungssystem | Protokolliert die Erstellung, Verarbeitung oder Auslieferung systemseitiger Benachrichtigungen. | | `shop.service.mailer` | Shop / E-Mail-Service | Protokolliert E-Mail-bezogene Vorgänge direkt aus dem Shopkontext. | #### Zahlungen und PayPal | **Technische Kategorie** | **Sprechende Bezeichnung** | **Beschreibung** | | ----------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `payment.block.ip` | Zahlungssperre / IP-Basis | Protokolliert den Sicherheitsmechanismus, der Brute-Force-Versuche bei Zahlungsarten auf Basis der IP-Adresse unterbindet. Nach zu vielen Fehlversuchen wird der Checkout für die betreffende IP-Adresse gesperrt. | | `payment.block.session` | Zahlungssperre / Sitzungsbasis | Protokolliert denselben Sicherheitsmechanismus auf Ebene der Sitzung. Nach zu vielen Fehlversuchen wird der Checkout für die betreffende Sitzung gesperrt. | | `paypalonboarding.buildrequest` | PayPal-Onboarding / Request-Aufbau | Protokolliert das Erstellen technischer Anfragen für das PayPal-Onboarding. | | `paypalonboarding.getaccesstoken` | PayPal-Onboarding / Access-Token | Protokolliert das Abrufen von Zugriffsdaten für PayPal-Onboarding-Prozesse. | | `paypalonboarding.getaccountstatus` | PayPal-Onboarding / Kontostatus | Protokolliert das Abfragen und Verarbeiten des PayPal-Kontostatus. | | `paypalonboarding.getactionurl` | PayPal-Onboarding / Aktions-URL abrufen | Protokolliert das Ermitteln einer für das Onboarding benötigten Aktions-URL. | | `paypalonboarding.parseactionurl` | PayPal-Onboarding / Aktions-URL auswerten | Protokolliert die technische Auswertung oder Aufbereitung einer Onboarding-URL. | #### Plugins | **Technische Kategorie** | **Sprechende Bezeichnung** | **Beschreibung** | | --------------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `plugin.account` | Plugin / Kundenkonto | Protokolliert pluginbezogene Vorgänge im Zusammenhang mit dem Kundenkonto. | | `plugin.actions` | Plugin / Aktionen | Protokolliert pluginbezogene Aktions- oder Steuerungsprozesse. | | `plugin.appTokenLogin` | Plugin / App-Token-Login | Protokolliert die Sonderbehandlung für die App. Damit wird erkannt, ob der Shop über die App aufgerufen wird. | | `plugin.appTrackingConsent` | Plugin / App-Tracking-Einwilligung | Protokolliert die Sonderbehandlung für die iOS-App. Dort sind keine Cookie-Banner zulässig, stattdessen wird das AppTrackingTransparency-Framework von Apple verwendet. | | `plugin.asse` | Plugin / ASSE | Protokolliert pluginbezogene Vorgänge rund um die ASSE-Schnittstelle. | | `plugin.autobasket` | Plugin / Automatischer Warenkorb | Protokolliert pluginbezogene Vorgänge zu Produkten, die automatisch in den Warenkorb gelegt werden. | | `plugin.autoLogin` | Plugin / Auto-Login | Protokolliert pluginbezogene Vorgänge beim automatischen Anmelden von Benutzern. | | `plugin.basket` | Plugin / Warenkorb | Protokolliert pluginbezogene Vorgänge im Warenkorb. | | `plugin.category` | Plugin / Kategorien | Protokolliert pluginbezogene Vorgänge auf Kategorieebene. | | `plugin.checkout` | Plugin / Checkout | Protokolliert pluginbezogene Vorgänge im Checkout. | | `plugin.computop-hosted` | Plugin / Computop Hosted | Protokolliert pluginbezogene Vorgänge der Zahlungsanbindung an Computop als Clearer. | | `plugin.config` | Plugin / Konfiguration | Protokolliert pluginbezogene Konfigurationszugriffe und Konfigurationsänderungen. | | `plugin.consent` | Plugin / Consent | Protokolliert pluginbezogene Vorgänge zu Einwilligungen und Zustimmungen. | | `plugin.cookie` | Plugin / Cookie | Protokolliert pluginbezogene Vorgänge rund um Cookies und Cookie-Verarbeitung. | | `plugin.core` | Plugin / Kernfunktionen | Protokolliert grundlegende pluginbezogene Kernprozesse. | | `plugin.customerData` | Plugin / Kundendaten | Protokolliert pluginbezogene Vorgänge mit Kundendaten. | | `plugin.directOrder` | Plugin / Direktbestellung | Protokolliert pluginbezogene Vorgänge bei Direktbestellungen. | | `plugin.emails` | Plugin / E-Mails | Protokolliert pluginbezogene E-Mail-Vorgänge. | | `plugin.externalData` | Plugin / Externe Daten | Protokolliert pluginbezogene Verarbeitung externer Datenquellen. | | `plugin.form` | Plugin / Formulare | Protokolliert pluginbezogene Formularvorgänge. | | `plugin.Inactive` | Plugin / Inaktiver Shop | Protokolliert pluginbezogene Vorgänge für inaktive Shops, beispielsweise einen Shop im Testmodus. | | `plugin.inventory` | Plugin / Bestand | Protokolliert pluginbezogene Vorgänge im Zusammenhang mit Beständen. | | `plugin.jsonFilter` | Plugin / JSON-Filter | Protokolliert pluginbezogene Verarbeitung von JSON-Filtern. | | `plugin.lastSeenProducts` | Plugin / Zuletzt angesehene Produkte | Protokolliert pluginbezogene Vorgänge zu zuletzt angesehenen Produkten. | | `plugin.maintenance` | Plugin / Wartungsmodus | Protokolliert pluginbezogene Vorgänge im Wartungsmodus. | | `plugin.navigation` | Plugin / Navigation | Protokolliert pluginbezogene Vorgänge in der Navigation. | | `plugin.newsletter` | Plugin / Newsletter | Protokolliert pluginbezogene Vorgänge rund um Newsletter. | | `plugin.optIn` | Plugin / Opt-In | Protokolliert pluginbezogene Opt-In-Prozesse. | | `plugin.options` | Plugin / Template-Optionen | Protokolliert pluginbezogene Vorgänge rund um Optionen in Templates. | | `plugin.orderHistory` | Plugin / Bestellhistorie | Protokolliert pluginbezogene Vorgänge zur Bestellhistorie. | | `plugin.payment` | Plugin / Zahlungsarten | Protokolliert pluginbezogene Vorgänge und Fehler in der Verarbeitung von Zahlungsarten. | | `plugin.paypal-checkout` | Plugin / PayPal Checkout | Protokolliert pluginbezogene Vorgänge im PayPal-Checkout. | | `plugin.pdfFilter` | Plugin / PDF-Filter | Protokolliert pluginbezogene Verarbeitung oder Filterung von PDF-Inhalten. | | `plugin.product` | Plugin / Produkte | Protokolliert pluginbezogene Vorgänge auf Produktebene. | | `plugin.productRating` | Plugin / Produktbewertungen | Protokolliert pluginbezogene Vorgänge zu Produktbewertungen. | | `plugin.requestVariables` | Plugin / Request-Variablen | Protokolliert pluginbezogene Verarbeitung von Request-Parametern und Variablen. | | `plugin.rest` | Plugin / REST | Protokolliert pluginbezogene REST-Prozesse. | | `plugin.routing` | Plugin / Routing | Protokolliert pluginbezogene Routing-Vorgänge. | | `plugin.search` | Plugin / Suche | Protokolliert pluginbezogene Suchvorgänge. | | `plugin.security` | Plugin / Sicherheit | Protokolliert pluginbezogene Sicherheitsprüfungen und sicherheitsrelevante Ereignisse. | | `plugin.session` | Plugin / Sitzung | Protokolliert pluginbezogene Sitzungsverwaltung. | | `plugin.shipTrack` | Plugin / Sendungsverfolgung | Protokolliert pluginbezogene Vorgänge zur Sendungsverfolgung. | | `plugin.statistics` | Plugin / Statistik | Protokolliert pluginbezogene Statistik- und Auswertungsvorgänge. | | `plugin.storage` | Plugin / Lager | Protokolliert pluginbezogene Vorgänge rund um Lager und Lagerdaten. | | `plugin.stores` | Plugin / Filialen | Protokolliert pluginbezogene Vorgänge im Zusammenhang mit Filialen oder Standorten. | | `plugin.stripe` | Plugin / Stripe | Protokolliert pluginbezogene Vorgänge im Zusammenhang mit Stripe. | | `plugin.subshop` | Plugin / Subshop | Protokolliert pluginbezogene Vorgänge für Subshops. | | `plugin.Test` | Plugin / Test | Protokolliert pluginbezogene Test- oder Prüfprozesse. | | `plugin.views` | Plugin / Ansichten | Protokolliert pluginbezogene Vorgänge in Ansichten oder Darstellungen. | | `plugin.voucher` | Plugin / Gutschein | Protokolliert pluginbezogene Vorgänge zu Gutscheinen. | | `plugin.watchList` | Plugin / Merkliste | Protokolliert pluginbezogene Vorgänge im Zusammenhang mit Merklisten. | #### Programme und Hintergrundprozesse | **Technische Kategorie** | **Sprechende Bezeichnung** | **Beschreibung** | | ---------------------------------------------- | -------------------------------------------------- | --------------------------------------------------------------------------------------------- | | `program.appAutomation` | Programm / Automatisierung | Protokolliert automatisierte Hintergrundprozesse der Anwendung. | | `program.asse` | Programm / ASSE | Protokolliert Hintergrundprozesse rund um die ASSE-Schnittstelle. | | `program.backInStock` | Programm / Back-in-Stock | Protokolliert Hintergrundprozesse für Benachrichtigungen zur Wiederverfügbarkeit. | | `program.cache` | Programm / Cache | Protokolliert allgemeine Cache-bezogene Hintergrundprozesse. | | `program.cache.main` | Programm / Cache / Hauptprozess | Protokolliert den zentralen Ablauf der Cache-Verarbeitung. | | `program.cache.rebuildCategoryCacheForShop` | Programm / Cache / Kategoriedaten neu aufbauen | Protokolliert den Neuaufbau von Cache-Daten für Kategorien. | | `program.cache.rebuildConfigCacheForShop` | Programm / Cache / Konfiguration neu aufbauen | Protokolliert den Neuaufbau von Cache-Daten für Konfigurationen. | | `program.cache.rebuildTranslationCacheForShop` | Programm / Cache / Übersetzungen neu aufbauen | Protokolliert den Neuaufbau von Cache-Daten für Übersetzungen. | | `program.captureExecutor` | Programm / Capture-Ausführung | Protokolliert Hintergrundprozesse zur Ausführung von Capture-Vorgängen. | | `program.captureExecutor.capturePayment` | Programm / Capture / Zahlung erfassen | Protokolliert das technische Erfassen oder Finalisieren von Zahlungen. | | `program.captureExecutor.main` | Programm / Capture / Hauptprozess | Protokolliert den zentralen Ablauf der Capture-Verarbeitung. | | `program.captureExecutor.processFile` | Programm / Capture / Datei verarbeiten | Protokolliert die Verarbeitung von Dateien innerhalb des Capture-Prozesses. | | `program.captureExecutor.watchDirectory` | Programm / Capture / Verzeichnis überwachen | Protokolliert die Überwachung von Verzeichnissen für Capture-relevante Dateien oder Prozesse. | | `program.customerReminder` | Programm / Kundenerinnerung | Protokolliert automatisierte Prozesse für Kundenerinnerungen. | | `program.customerReminder.middleware` | Programm / Kundenerinnerung / Middleware | Protokolliert technische Zwischenschritte in der Verarbeitung von Kundenerinnerungen. | | `program.eventqueuetask` | Programm / Event-Queue-Task | Protokolliert Hintergrundaufgaben zur Verarbeitung von Ereigniswarteschlangen. | | `program.exchangeRates` | Programm / Wechselkurse | Protokolliert automatisierte Prozesse zur Verarbeitung von Wechselkursen. | | `program.exchangeRates.main` | Programm / Wechselkurse / Hauptprozess | Protokolliert den zentralen Ablauf der Wechselkursverarbeitung. | | `program.garbageCollector` | Programm / Bereinigung | Protokolliert automatische Bereinigungs- und Aufräumprozesse. | | `program.garbageCollector.main` | Programm / Bereinigung / Hauptprozess | Protokolliert den zentralen Ablauf der Bereinigungsprozesse. | | `program.hreflangCollector` | Programm / hreflang-Ermittlung | Protokolliert Prozesse zum Sammeln oder Ermitteln von hreflang-Informationen. | | `program.hreflangCollector.main` | Programm / hreflang-Ermittlung / Hauptprozess | Protokolliert den zentralen Ablauf der hreflang-Verarbeitung. | | `program.indexer` | Programm / Indexer | Protokolliert Hintergrundprozesse zur Indexierung von Daten. | | `program.migrate` | Programm / Migration | Protokolliert technische Migrationsprozesse, z. B. bei Daten- oder Strukturänderungen. | | `program.notificator` | Programm / Benachrichtigungssystem | Protokolliert automatisierte Benachrichtigungsprozesse. | | `program.notificator.main` | Programm / Benachrichtigungssystem / Hauptprozess | Protokolliert den zentralen Ablauf der Benachrichtigungsverarbeitung. | | `program.orderchecker` | Programm / Bestellprüfung | Protokolliert automatisierte Prüfprozesse rund um Bestellungen. | | `program.orderchecker.checkorder` | Programm / Bestellprüfung / Bestellung prüfen | Protokolliert die technische Prüfung einzelner Bestellungen. | | `program.orderchecker.completeOrder` | Programm / Bestellprüfung / Bestellung abschließen | Protokolliert technische Schritte beim Abschluss von Bestellungen. | | `program.orderchecker.main` | Programm / Bestellprüfung / Hauptprozess | Protokolliert den zentralen Ablauf der Bestellprüfung. | | `program.seogenerator` | Programm / SEO-Generierung | Protokolliert Hintergrundprozesse zur Generierung von SEO-Daten, insbesondere von SEO-URLs. | | `program.sitemapgenerator` | Programm / Sitemap-Generierung | Protokolliert Hintergrundprozesse zur Erstellung von Sitemaps. | | `program.statisticAggregator` | Programm / Statistik-Aggregation | Protokolliert die Zusammenführung und Aufbereitung statistischer Daten. | | `program.statisticAggregator.main` | Programm / Statistik-Aggregation / Hauptprozess | Protokolliert den zentralen Ablauf der Statistik-Aggregation. | | `program.templateCompiler.main` | Programm / Template-Kompilierung / Hauptprozess | Protokolliert den zentralen Ablauf der Template-Kompilierung. | | `program.workqueuetask` | Programm / Work-Queue-Task | Protokolliert Hintergrundaufgaben zur Verarbeitung interner Arbeitswarteschlangen. | #### Automatisierung und Messaging | **Technische Kategorie** | **Sprechende Bezeichnung** | **Beschreibung** | | ---------------------------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- | | `appAutomation::messageValidCheck` | Automatisierung / Nachrichtenvalidierung | Protokolliert beim Versand von Push-Nachrichten die Prüfung, ob eine Nachricht noch gültig und nicht abgelaufen ist. | | `appAutomation.FilterListCleanup` | Automatisierung / Filterlisten-Bereinigung | Protokolliert die automatische Bereinigung oder Aktualisierung von Filterlisten. | | `captureExecutor` | Capture-Ausführung | Protokolliert Vorgänge und Fehler bei der technischen Ausführung von Capture-Prozessen. | | `RabbitMQ` | RabbitMQ | Protokolliert allgemeine Vorgänge und Fehler in der Messaging-Infrastruktur auf Basis von RabbitMQ. | | `RabbitMQReceiver` | RabbitMQ / Empfänger | Protokolliert das Empfangen und Verarbeiten eingehender Nachrichten über RabbitMQ. | | `RabbitMQSender` | RabbitMQ / Sender | Protokolliert das Versenden ausgehender Nachrichten über RabbitMQ. | #### REST-API | **Technische Kategorie** | **Sprechende Bezeichnung** | **Beschreibung** | | ---------------------------------------- | ----------------------------- | --------------------------------------------------------------------------------------------------- | | `restapi.authentication` | REST-API / Authentifizierung | Protokolliert Vorgänge und Fehler bei der Authentifizierung für REST-API-Zugriffe. | | `restapi.controller.statistics` | REST-API / Statistik | Protokolliert REST-API-Vorgänge im Zusammenhang mit Statistikdaten und Auswertungen. | | `restapi.controllers.administration` | REST-API / Administration | Protokolliert Vorgänge und Fehler in administrativen REST-API-Funktionen. | | `restapi.controllers.app` | REST-API / App | Protokolliert appbezogene Zugriffe und Verarbeitungsschritte über die REST-API. | | `restapi.controllers.blacklist` | REST-API / Blacklist | Protokolliert REST-API-Vorgänge im Zusammenhang mit Blacklists oder Sperrlisten. | | `restapi.controllers.categories` | REST-API / Kategorien | Protokolliert REST-API-Vorgänge für Kategorien. | | `restapi.controllers.configuration` | REST-API / Konfiguration | Protokolliert REST-API-Zugriffe auf Konfigurationsdaten und Konfigurationsänderungen. | | `restapi.controllers.customers` | REST-API / Kunden | Protokolliert REST-API-Vorgänge im Zusammenhang mit Kundendaten. | | `restapi.controllers.datafeeds` | REST-API / Datenfeeds | Protokolliert REST-API-Vorgänge für Datenfeeds. | | `restapi.controllers.exchange_rates` | REST-API / Währungsumrechnung | Protokolliert REST-API-Vorgänge zur Währungsumrechnung. | | `restapi.controllers.golive` | REST-API / Shop-Livegang | Protokolliert REST-API-Vorgänge zur Absicherung des Shop-Livegangs. | | `restapi.controllers.image` | REST-API / Bilder | Protokolliert REST-API-Vorgänge rund um Bilddaten und Bildverarbeitung. | | `restapi.controllers.import` | REST-API / Import | Protokolliert REST-API-gestützte Importvorgänge. | | `restapi.controllers.inquiry` | REST-API / Anfragen | Protokolliert REST-API-Vorgänge zu Anfragen oder Kontaktanliegen. | | `restapi.controllers.logmanager` | REST-API / LogManager | Protokolliert Zugriffe und Vorgänge im Zusammenhang mit dem LogManager über die REST-API. | | `restapi.controllers.maintenance` | REST-API / Wartungsmodus | Protokolliert REST-API-Vorgänge, mit denen der Shop in einen Wartungsmodus geschaltet werden kann. | | `restapi.controllers.newsletter` | REST-API / Newsletter | Protokolliert REST-API-Vorgänge im Zusammenhang mit Newslettern. | | `restapi.controllers.order` | REST-API / Bestellungen | Protokolliert REST-API-Vorgänge rund um Bestellungen. | | `restapi.controllers.paypalonboarding` | REST-API / PayPal-Onboarding | Protokolliert REST-API-Vorgänge für das PayPal-Onboarding. | | `restapi.controllers.productrating` | REST-API / Produktbewertungen | Protokolliert REST-API-Vorgänge zu Produktbewertungen. | | `restapi.controllers.products` | REST-API / Produkte | Protokolliert REST-API-Vorgänge für Produkte. | | `restapi.controllers.products_inventory` | REST-API / Produktbestände | Protokolliert REST-API-Vorgänge im Zusammenhang mit Produktbeständen. | | `restapi.controllers.productvariants` | REST-API / Produktvarianten | Protokolliert REST-API-Vorgänge für Produktvarianten. | | `restapi.controllers.reporter` | REST-API / Reporting | Protokolliert REST-API-Vorgänge für Reports und Auswertungen. | | `restapi.controllers.seoTexts` | REST-API / SEO-Texte | Protokolliert REST-API-Vorgänge zu SEO-Texten. | | `restapi.controllers.seourl` | REST-API / SEO-URLs | Protokolliert REST-API-Vorgänge für SEO-URLs. | | `restapi.controllers.shop_rent` | REST-API / Shop-Miete | Protokolliert REST-API-Vorgänge im Zusammenhang mit shopbezogenen Miet- oder Laufzeitinformationen. | | `restapi.controllers.sitemaps` | REST-API / Sitemaps | Protokolliert REST-API-Vorgänge zu Sitemaps. | | `restapi.controllers.storage` | REST-API / Lager | Protokolliert REST-API-Vorgänge für Lagerdaten. | | `restapi.controllers.store` | REST-API / Filialen | Protokolliert REST-API-Vorgänge im Zusammenhang mit Filialen oder Standorten. | | `restapi.controllers.strapi` | REST-API / Strapi | Protokolliert REST-API-Vorgänge in Verbindung mit Strapi. | | `restapi.controllers.stripeonboarding` | REST-API / Stripe-Onboarding | Protokolliert REST-API-Vorgänge für das Stripe-Onboarding. | | `restapi.controllers.templates` | REST-API / Templates | Protokolliert REST-API-Vorgänge zu Templates und Vorlagen. | | `restapi.controllers.text` | REST-API / Texte | Protokolliert REST-API-Vorgänge für Textinhalte. | | `restapi.controllers.transactions` | REST-API / Transaktionen | Protokolliert REST-API-Vorgänge im Zusammenhang mit Transaktionen. | | `restapi.controllers.video` | REST-API / Videos | Protokolliert REST-API-Vorgänge rund um Videos und Videodaten. | | `restapi.controllers.vouchers` | REST-API / Gutscheine | Protokolliert REST-API-Vorgänge im Zusammenhang mit Gutscheinen. | | `restapi.service.backInStock` | Back-in-Stock-Service | Protokolliert Servicevorgänge zur Verwaltung von Wiederverfügbarkeitsbenachrichtigungen. | #### Shop, Views und Frontend-nahe Prozesse | **Technische Kategorie** | **Sprechende Bezeichnung** | **Beschreibung** | | ------------------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------------- | | `shop.asse.service` | Shop / ASSE-Service | Protokolliert shopseitige Vorgänge rund um die ASSE-Schnittstelle. | | `shop.customerReminder.service` | Shop / Kundenerinnerung / Service | Protokolliert Servicevorgänge für Kundenerinnerungen im Shop. | | `shop.customerReminder.startup` | Shop / Kundenerinnerung / Start | Protokolliert Initialisierung und Start von Kundenerinnerungsfunktionen im Shop. | | `shop.middleware.errorHandling` | Shop / Fehlerbehandlung | Protokolliert Fehler, die bei der zentralen Behandlung und Verarbeitung von Shop-Fehlern auftreten. | | `shop.middleware.requestInfo` | Shop / Request-Informationen | Protokolliert technische Informationen zu eingehenden Shop-Anfragen. | | `shop.parseView` | Shop / View-Auswertung | Protokolliert die Verarbeitung und Aufbereitung von Shop-Ansichten. | | `shop.sendBackInStock.service` | Shop / Back-in-Stock-Versand / Service | Protokolliert den Versand und die Verarbeitung von Wiederverfügbarkeitsbenachrichtigungen im Shop. | | `shop.sendBackInStock.startup` | Shop / Back-in-Stock-Versand / Start | Protokolliert Initialisierung und Start des Versands von Wiederverfügbarkeitsbenachrichtigungen. | | `shop.startup` | Shop / Start | Protokolliert Initialisierung und Start zentraler Shopfunktionen. | | `shop.viewEnvironment` | Shop / View-Umgebung | Protokolliert den Aufbau und die Bereitstellung der technischen Umgebung für Shop-Ansichten. | #### SEO, Inhalte und sonstige Dienste | **Technische Kategorie** | **Sprechende Bezeichnung** | **Beschreibung** | | ------------------------ | -------------------------- | --------------------------------------------------------------------------------------------------------------------- | | `seotext.repository` | SEO-Texte / Repository | Protokolliert Zugriffe, Verarbeitung und Fehler im Zusammenhang mit gespeicherten SEO-Texten. | | `seoTextService` | SEO-Text-Service | Protokolliert Vorgänge und Fehler bei der Bereitstellung oder Verarbeitung von SEO-Texten. | | `SitemapBuilder` | Sitemap-Erstellung | Protokolliert Vorgänge und Fehler bei der Erstellung von Sitemaps. | | `statisticAggregator` | Statistik-Aggregation | Protokolliert die Zusammenführung und Aufbereitung statistischer Daten außerhalb der programmbezogenen Hauptprozesse. | | `templateCompiler.run` | Template-Kompilierung | Protokolliert die technische Verarbeitung und Kompilierung von Templates. | | `ShopRentService` | Shop-Miete-Service | Protokolliert Vorgänge und Fehler im Zusammenhang mit shopbezogenen Miet- oder Laufzeitdiensten. | ### Log-Level Legt fest, welche Art von Protokolleinträgen in der Log-Gruppe berücksichtigt werden. Das LogLevel beschreibt die Bedeutung bzw. Schwere eines Eintrags – von rein informativen Meldungen bis hin zu kritischen Fehlern. | **LogLevel** | **Beschreibung** | | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Debug** | Enthält sehr detaillierte technische Informationen für Analyse- und Diagnosezwecke. Dieses Level ist vor allem für Entwicklung und Fehlersuche relevant. | | **Info** | Enthält allgemeine Informationen über reguläre Abläufe und erfolgreich ausgeführte Prozesse. Diese Einträge dienen vor allem der Nachvollziehbarkeit. | | **Warnung** | Enthält Hinweise auf Auffälligkeiten oder potenzielle Probleme, bei denen ein Vorgang zwar noch ausgeführt werden konnte, aber geprüft werden sollte. | | **Fehler** | Enthält Fehlermeldungen zu Problemen, durch die einzelne Vorgänge nicht korrekt ausgeführt werden konnten oder abgebrochen wurden. | | **Kritischer Fehler** | Enthält besonders schwerwiegende Fehlermeldungen, die auf akute Störungen oder Ausfälle wichtiger Funktionen hinweisen. Diese Einträge sollten zeitnah geprüft werden. | ### Programm Über das Feld *Programm* wird festgelegt, aus welchem technischen Dienst oder Verarbeitungsbereich Protokolleinträge in die Log-Gruppe aufgenommen werden. Da die technischen Namen nicht immer selbsterklärend sind, empfiehlt sich für die Anzeige eine sprechende Bezeichnung mit zusätzlicher Angabe des technischen Namens. | **Technischer Name** | **Sprechende Bezeichnung** | **Beschreibung** | | --------------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | `appapi` | App-API | Protokolliert Vorgänge und Fehler im Zusammenhang mit der App-API. | | `appAutomation` | Automatisierung | Protokolliert automatisierte Abläufe und Hintergrundverarbeitungen der Anwendung. | | `asse` | ASSE-Schnittstelle | Protokolliert Vorgänge und Fehler bei der asynchronen serverseitigen Kommunikation mit externen Systemen. | | `backInStock` | Wiederverfügbarkeits-Benachrichtigungen | Protokolliert Vorgänge und Fehler bei Benachrichtigungen zur Wiederverfügbarkeit von Produkten. | | `cache` | Cache-Verwaltung | Protokolliert Vorgänge und Fehler beim Aufbau, Aktualisieren oder Bereinigen von Cache-Daten. | | `captureExecutor` | Capture-Verarbeitung | Protokolliert Vorgänge und Fehler bei der technischen Ausführung von Capture-Prozessen, z. B. im Zahlungsumfeld. | | `categoryProductsRebuilder` | Neuaufbau von Kategorieprodukten | Protokolliert Vorgänge und Fehler beim Neuaufbau von Produktzuordnungen innerhalb von Kategorien. | | `configUpdater` | Konfigurationsaktualisierung | Protokolliert Vorgänge und Fehler beim Verteilen und Aktualisieren von Konfigurationsdaten. | | `customerReminder` | Kundenerinnerungen | Protokolliert Vorgänge und Fehler bei automatisch versendeten Erinnerungen an Kunden. | | `exchangeRates` | Wechselkursverarbeitung | Protokolliert Vorgänge und Fehler beim Abrufen, Verarbeiten oder Aktualisieren von Wechselkursen. | | `feedBuilder` | Datenfeed-Erstellung | Protokolliert Vorgänge und Fehler bei der Erstellung und Ausgabe von Datenfeeds. | | `garbageCollector` | Bereinigung und Aufräumprozesse | Protokolliert automatische Bereinigungs- und Aufräumvorgänge im System. | | `hreflangCollector` | hreflang-Verarbeitung | Protokolliert Vorgänge und Fehler beim Ermitteln und Verarbeiten von hreflang-Informationen. | | `html2mime` | HTML-zu-MIME-Verarbeitung | Protokolliert Vorgänge und Fehler bei der Umwandlung von HTML-Inhalten in MIME-kompatible Formate, z. B. für E-Mails. | | `imageChecker` | Bildprüfung | Protokolliert Prüfungen und Fehler bei der Kontrolle von Bilddateien. | | `imageconverter` | Bildkonvertierung | Protokolliert Vorgänge und Fehler bei der Umwandlung und Verarbeitung von Bildern. | | `importer` | Produktimporte | Protokolliert Vorgänge und Fehler beim Import von Produktdaten. | | `inputAssistant` | Eingabehilfen und Assistenten | Protokolliert Vorgänge und Fehler in Funktionen, die Benutzer bei Eingaben unterstützen oder durch Eingaben führen. | | `mailbackup` | E-Mail-Archivierung | Protokolliert Vorgänge und Fehler beim Sichern oder Archivieren von E-Mails. | | `mailer` | E-Mail-Versand | Protokolliert Vorgänge und Fehler beim Versand von E-Mails. | | `manage` | Systemverwaltung | Protokolliert administrative und verwaltungsbezogene Systemvorgänge. | | `migrate` | Migrationen | Protokolliert technische Migrationsprozesse, z. B. bei Daten- oder Strukturänderungen. | | `newsletterSubscribeHelper` | Newsletter-Anmeldung | Protokolliert Vorgänge und Fehler bei der Anmeldung zu Newslettern. | | `notificator` | Benachrichtigungssystem | Protokolliert Vorgänge und Fehler bei der Erstellung, Verarbeitung oder Zustellung von Benachrichtigungen. | | `orderchecker` | Bestellprüfung | Protokolliert Vorgänge und Fehler bei der automatisierten Prüfung und Verarbeitung von Bestellungen. | | `perftests` | Performance-Tests | Protokolliert technische Test- und Messvorgänge zur Überprüfung der Systemleistung. | | `restapi` | REST-API | Protokolliert Vorgänge und Fehler bei Zugriffen und Verarbeitungen über die REST-API. | | `searchindexer` | Suchindex-Verarbeitung | Protokolliert Vorgänge und Fehler beim Aufbau und Aktualisieren von Suchindizes. | | `seourlgenerator` | SEO-URL-Generierung | Protokolliert Vorgänge und Fehler bei der Generierung von SEO-URLs. | | `setup` | Einrichtung und Setup | Protokolliert Vorgänge und Fehler bei Einrichtung, Initialkonfiguration oder technischen Setup-Prozessen. | | `shop` | Shop-Anwendung | Protokolliert allgemeine Vorgänge und Fehler im laufenden Shopbetrieb. | | `shop-wrapper` | Shop-Wrapper | Protokolliert technische Vorgänge in der umgebenden Shop-Laufzeit oder Integrationsschicht. | | `sitemapgenerator` | Sitemap-Generierung | Protokolliert Vorgänge und Fehler bei der Erstellung von Sitemaps. | | `statisticaggregator` | Statistik-Aggregation | Protokolliert Vorgänge und Fehler bei der Zusammenführung und Aufbereitung statistischer Daten. | | `storefrontApiCompiler` | Storefront-API-Compiler | Protokolliert Vorgänge und Fehler bei der technischen Aufbereitung oder Kompilierung für die Storefront-API. | | `templateCompiler` | Template-Kompilierung | Protokolliert Vorgänge und Fehler bei der Verarbeitung und Kompilierung von Templates. | ### Schlüsselwort Inhaltssuche in den Log-Dateien selbst Über das Schlüsselwort können Log-Einträge zusätzlich anhand ihres Inhalts gefiltert werden. So lässt sich die Log-Gruppe gezielt auf bestimmte Fehlermeldungen, technische Begriffe oder Errorcodes eingrenzen. So kann z. B. eine Log-Gruppe für kritische Fehler zusätzlich auf bestimmte Fehlermeldungen oder bekannte Errorcodes eingeschränkt werden. ### Subshops Über diesen Filter kann festgelegt werden, für welche Subshops Protokolleinträge in die Log-Gruppe aufgenommen werden. So lässt sich die Protokollierung in Multi-Shop-Umgebungen gezielt auf einzelne Shopbereiche eingrenzen. Das ist besonders sinnvoll, wenn eine Plattform mehrere Subshops enthält und Logs nur für einen bestimmten Shop ausgewertet werden sollen. *** ## E-Mail-Benachrichtigungen Für Log-Gruppen können optional E-Mail-Benachrichtigungen eingerichtet werden. So lässt sich festlegen, dass bei neu erfassten Log-Einträgen automatisch eine Benachrichtigung per E-Mail versendet wird. Der Versand erfolgt nicht bei jedem einzelnen Eintrag sofort, sondern auf Basis eines konfigurierbaren Zeitintervalls. Zusätzlich kann angegeben werden, ab welchem Datum und zu welcher Uhrzeit die erste Benachrichtigung versendet werden soll. Ab diesem Zeitpunkt gilt dann das eingestellte Intervall für weitere Benachrichtigungen. Als Empfänger können eine oder mehrere E-Mail-Adressen hinterlegt werden. In den Benachrichtigungs-E-Mails sind Links zum Dienst sowie zur zugehörigen Log-Gruppe enthalten, damit die betreffenden Einträge direkt aufgerufen werden können. Standardmäßig werden keine E-Mail-Benachrichtigungen versendet. Eine Benachrichtigung erfolgt nur, wenn diese Funktion für die jeweilige Log-Gruppe ausdrücklich konfiguriert wurde. # Bekannte Fehlermeldungen Source: https://dokumentation.websale.de/admin-interface/logs-und-statistiken/bekannte-fehlermeldungen Antworten und Lösungen für bekannte Fehlermeldungen aus dem LogManager. Auf dieser Seite werden bekannte Meldungen aus dem [LogManager](/admin-interface/logmanager-logs) gesammelt und beantwortet. Zu jeder Fehlermeldung erfahren Sie, wie der Fehler entsteht und welche Maßnahmen Sie ergreifen können, um den Fehler zu beheben. Fehler, die nicht durch eigene Konfiguration lösbar sind, sind entsprechend gekennzeichnet. Wie Sie Log-Gruppen anlegen, welche Filter es gibt und was die Log-Level bedeuten, erfahren Sie auf der Seite [LogManager (Logs)](/admin-interface/logmanager-logs). Wenn eine Ursache unklar bleibt, wenden Sie sich bitte an das [WEBSALE Service Desk](https://websale.atlassian.net/servicedesk/customer/portal/6) und nennen Sie dabei immer die Bestellnummer, den Subshop und den Zeitraum. *** ## Zahlungsabwicklung ### `... but the clearer provides no failure url. The customer stays on the page the clearer returned to. Configure an error template for this payment method.` Nachrichten-ID: `paymentCheckBeforeRoute.missingFailureRedirectUrl` ####
    Symptom Der Kunde bleibt auf der Seite, auf die er vom Zahlungsanbieter zurückgeschickt wurde. In der Regel ist das die reguläre Checkout- oder Pending-Seite. Es kommt zu keinem Absturz und es wird keine leere Seite angezeigt. #### Ursache Eine Zahlung ist in einem Status geendet, für den eigentlich eine eigene Fehlerseite benötigt wird (beispielsweise `canceledByUser` ). Für den aktuellen Zahlungsanbieter ist jedoch keine eigene Fehlerweiterleitung implementiert. **Wichtig:**
    Die Fehlermeldung "`Configure an error template`" klingt, als würde eine Admin-Einstellung fehlen. Für Stripe (Payment-IDs beginnen mit "`pi_`") gibt es diese Funktion aktuell jedoch nicht. Nur die PayPal-Integration hat eine eigene Fehlerseiten-Konfiguration. Bei Stripe handelt es sich also nicht um einen Konfigurationsfehler, den man selbst beheben kann, sondern um eine aktuell fehlende Funktion in der Integration.
    #### Vorgehen In der Meldung werden die Transaktions-ID und die Bestellnummer genannt. Welcher Zahlungsanbieter dahintersteht, sehen Sie an der Transaktion im Admin-Interface. Ein schneller Anhaltspunkt ist die Transaktions-ID: Transaktions-IDs von Stripe beginnen üblicherweise mit `pi_`. Einzelne Treffer sind unkritisch, denn der Kunde landet auf einer nutzbaren Seite und kann die Bestellung erneut versuchen. Ein Ticket ist dafür nicht nötig. Wenn sich die Meldung häuft und Kunden den Kaufvorgang nachweislich abbrechen, weil sie auf der Pending-Seite ohne Rückmeldung stehen bleiben, melden Sie das bitte als Funktionswunsch bei WEBSALE. Über die Shop-Konfiguration ist diese Problematik nicht lösbar. *** ### `Failed to handle webhook: ` Nachrichten-ID: `paymentCheckBeforeRoute.handleHook` ####
    Symptom Ein vom Zahlungsanbieter gemeldetes Ergeignis wird nicht verarbeitet. Der Zahlungsstatus der betroffenen Bestellung bleibt unverändert. Der Shop antwortet dem Zahlungsanbieter mit dem HTTP-Status `400`. Daraufhin wiederholt dieser die Zustellung über längere Zeit. #### Ursache PayPal und Stripe benachrichtigen den Shop im Hintergrund über Ereignisse zu einer Bestellung, beispielsweise "Zahlung eingegangen". Diese Benachrichtigungen laufen über eine zentrale Stelle im Shop, die für beide Anbieter dieselbe ist. Beim Eingang wird zunächst `Received webhook` auf Log-Level "Info" protokolliert. Schlägt die Verarbeitung danach fehl, protokolliert dieselbe Stelle `Failed to handle webhook:` gefolgt von einem kurzen Grund. Die Meldung ist somit keine eigenständige Fehlerursache, sondern eine Überschrift für mehrere sehr unterschiedliche Probleme. Entscheidend ist der Text hinter dem Doppelpunkt. | **Grund** | **Zahlungsart** | **Bedeutung** | | ---------------------------------------------------------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Webhook Validation FAILURE` | PayPal und Stripe | Die Signaturprüfung der eingehenden Benachrichtigung ist fehlgeschlagen. Entweder stammt die Anfrage nicht vom Zahlungsanbieter oder die im Shop hinterlegten Zugangsdaten zur Prüfung der Signatur sind nicht mehr korrekt. | | `Internal error while validating order` | PayPal | Die Rückfrage bei PayPal nach dem aktuellen Bestellstatus ist fehlgeschlagen oder hat einen unerwarteten Status geliefert. Siehe [Internal error while validating order](#internal-error-while-validating-order-payment-is-in-invalid-state-setting-payment-to-error-checkoutcapture-response-status-is-not-valid-regular). | | `ERROR, Order Validation FAILURE` | PayPal | Die von PayPal gelieferten Bestelldaten, beispielsweise der Betrag oder die Artikel, entsprechen nicht den Erwartungen des Shops. | | `unknown clearer order status in paypal checkout hook: ` | PayPal | PayPal meldet einen Bestellstatus, den der Shop an dieser Stelle nicht verarbeiten kann. | | `transaction not found` | PayPal | Im Shop gibt es zu der Benachrichtigung keine passende Transaktion. | | `failed to parse stripe event:
    ` | Stripe | Der von Stripe gesendete Inhalt war technisch fehlerhaft und konnte deshalb nicht gelesen werden. | | `Stripe event type not supported: ` | Stripe | Stripe hat ein Ereignis geschickt, das der Shop nicht auswertet. Verarbeitet werden nur `payment_intent.succeeded` und `payment_intent.payment_failed`. | | `not supported for this payment type` | alle übrigen | Für diese Zahlungsart werden im Shop keine Benachrichtigungen verarbeitet. Computop sendet selbst keine, daher entsteht dieser Fall im Normalbetrieb nicht. Er deutet auf eine fehlgeleitete oder manuell aufgerufene Webhook-Adresse hin. | Wenn die Zahlung bereits einen endgültigen Status hat, antwortet der Shop mit dem HTTP-Status 200 und protokolliert stattdessen `paymentCheckBeforeRoute.handleHookAlreadyFinalized`. In diesem Fall wiederholt der Zahlungsanbieter die Zustellung nicht. Die Nachrichten-ID `paymentCheckBeforeRoute.handleHook` wird auch für die Info-Meldung `Received webhook` verwendet. Eine Log-Gruppe, die nur auf diese Nachrichten-ID filtert, enthält deshalb auch alle erfolgreich verarbeiteten Webhooks. Grenzen Sie deshalb zusätzlich über das Log-Level ein. #### Vorgehen Lesen Sie den vollständigen Text hinter `Failed to handle webhook:`. Die Nachrichten-ID allein genügt nicht, denn sie ist bei allen Gründen dieselbe. Kontrollieren Sie die für die Signaturprüfung hinterlegten Zugangsdaten des betroffenen Zahlungsanbieters. Prüfen Sie außerdem, ob kurz davor ungewöhnliche Zugriffe im Log auftauchen, denn eine fehlgeschlagene Signaturprüfung kann auch ein Zugriffsversuch von außen sein. Bei Stripe grenzen die Meldungen `stripe.timestampInvalid` und `stripe.timestampTooOld` den Grund weiter ein. Erscheint keine von beiden, passte die Signatur selbst nicht. Lautet der Grund `Internal error while validating order`, folgen Sie dem eigenen Eintrag zu dieser Meldung. Lautet er `ERROR, Order Validation FAILURE` oder `unknown clearer order status in paypal checkout hook`, prüfen Sie die betroffene Bestellung im Admin-Interface daraufhin, ob sie bei PayPal in einem unerwarteten Zustand hängt. `failed to parse stripe event` und `Stripe event type not supported` sind in der Regel unkritisch, denn Stripe sendet auch Ereignistypen, die der Shop bewusst nicht auswertet. Erst wenn derselbe Ereignistyp gehäuft auftritt, lohnt sich eine Rückfrage bei WEBSALE, ob dieser Typ ergänzt werden sollte. Suchen Sie im selben Zeitfenster nach der Nachrichten-ID `paymentCheckBeforeRoute.handleHookResponseStatus`. Diese Meldung steht auf Log-Level "Info" und nennt den an den Zahlungsanbieter gesendeten HTTP-Status sowie die Bestellnummer und die Transaktions-ID. Nach einer Antwort mit dem HTTP-Status 400 stellt der Zahlungsanbieter denselben Webhook wiederholt zu. Mehrfache Treffer zu derselben Bestellung sind deshalb kein neues Problem, sondern Wiederholungen desselben Falls. Vereinzelte Treffer sind meist unauffällig. Tritt derselbe Grund gehäuft auf, melden Sie ihn bitte bei WEBSALE mit einigen Beispielzeitpunkten und Bestellnummern, denn ein dauerhaft fehlschlagender Endpunkt kann vom Zahlungsanbieter abgeschaltet werden. *** ### `Failed to create clearing request: ` Nachrichten-ID: `checkout.onlineClearingTransactionCreationFailed` ####
    Symptom Der Kunde kann die Bestellung nicht abschließen. Anstatt zur Bezahlseite des Zahlungsanbieters weitergeleitet zu werden, bleibt er im Checkout-Prozess und erhält die im Shop für `clearingFailure` hinterlegte Fehlermeldung. Der Shop setzt den Zahlungsstatus der Bestellung auf "Fehler" und macht bereits verbuchte Beträge wieder rückgängig. #### Ursache Bevor der Kunde zur Zahlung weitergeleitet wird, meldet der Shop den Zahlvorgang beim Zahlungsanbieter an. Diese Anmeldung ist fehlgeschlagen, sodass gar kein Zahlungsvorgang beginnen konnte. Die Meldung gilt für alle Online-Zahlungsanbieter. Der Grund dahinter stammt aus der jeweiligen Zahlungsart. Bei PayPal lautet der Grund `unable to create order`. Unmittelbar davor erscheint die Meldung `createRequest: unable to create order` mit der Nachrichten-ID `paypalCheckout.createRequestOrderError`. Warum die Anmeldung bei PayPal scheiterte, verrät erst eine weitere Meldung kurz davor: | **Nachrichten-ID** | **Bedeutung** | | --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `paypalCheckoutService.callApiHttpError` | PayPal hat geantwortet, aber mit einem Fehlercode. Die Bedeutung der Codes steht unter [Error setting up the connection to paypal api](#error-setting-up-the-connection-to-paypal-api-http-404). Direkt danach steht der Original-Antworttext von PayPal unter `paypalCheckoutService.callApiHttpErrorResult`. | | `paypalCheckoutService.callApiCurlError` | Die Verbindung zu PayPal kam gar nicht zustande, beispielsweise durch ein Netzwerkproblem oder eine Zeitüberschreitung. Für Verbindungsaufbau und Gesamtdauer gelten jeweils 10 Sekunden. PayPal hat in diesem Fall nicht geantwortet. | | `paypalCheckoutService.callApiCurlInitFailed` | Ein technisches Problem im Shop selbst beim Aufbau der Anfrage. Sehr selten und eher ein Hinweis auf ein Infrastrukturproblem als auf PayPal oder die Konfiguration. | Es gibt zwei weitere Gründe, die an derselben Stelle vor dem Aufruf bei PayPal entstehen: * `paypalCheckout.createRequestPayloadError`, wenn der Shop die Bestelldaten für PayPal nicht aufbauen konnte, und * `paypalCheckout.createRequestNoId` , wenn die Antwort von PayPal keine Bestell-ID enthält. Bei einem Authentifizierungsfehler mit dem HTTP-Status 401 holt der Shop automatisch ein frisches Zugriffstoken und wiederholt die Anfrage einmal. Erscheint der Fehler trotzdem, stimmen die hinterlegte Client-ID oder das Secret nicht. #### Vorgehen Suchen Sie zeitlich direkt vor dieser Meldung nach `paypalCheckoutService.callApiHttpError` und `paypalCheckoutService.callApiCurlError`. Daran sehen Sie, ob PayPal überhaupt geantwortet hat und mit welchem Statuscode, oder ob die Verbindung gar nicht erst zustande kam. Liegt ein HTTP-Statuscode vor, prüfen Sie den Eintrag `paypalCheckoutService.callApiHttpErrorResult` direkt danach. Er enthält PayPals Original-Fehlertext und benennt konkret, was PayPal bemängelt hat. Kontrollieren Sie Client-ID, Secret und den Betriebsmodus. Sandbox und Live sowie die hinterlegten Zugangsdaten müssen zusammenpassen, besonders nach einem kürzlichen Wechsel. Der Fehlertext aus Schritt 2 weist meist auf ein konkretes Feld hin, beispielsweise Betrag, Währung oder Adresse. Tritt der Fehler wiederholt mit demselben Feld auf, melden Sie das bitte bei WEBSALE. Bei `callApiCurlError` prüfen Sie, ob es ein einmaliger Ausreißer war oder ob PayPal gerade größere Störungen hat. Tritt der Fehler gehäuft auf, melden Sie ihn bitte bei WEBSALE. Vereinzelte Treffer durch kurze Verbindungs- oder Serverprobleme sind normal. Häufen sich die Fehler oder betreffen sie mehrere Kunden gleichzeitig, sollten Sie zeitnah melden, denn dann können Kunden mit dieser Zahlungsart überhaupt nicht bezahlen. *** ## PayPal Checkout ### `Failed to load payment status for order:Payment is in invalid state setting payment to error: checkoutCapture: response status is not valid (regular)` Nachrichten-ID: `paymentCheckBeforeRoute.clearerStatusUpdateFailed` ####
    Symptom Eine über PayPal begonnene Bestellung wird nicht als bezahlt bestätigt. Sie behält im Shop den Zahlungsstatus, den sie vor dem Abgleich hatte. In den allermeisten Fällen liegt das daran, dass der Kunde den Vorgang im PayPal-Fenster nicht zu Ende geführt hat. #### Ursache Der Shop fragt den PayPal-Auftragsstatus ab, um die Zahlung zu bestätigen. An dieser Stelle akzeptiert er für eine reguläre PayPal-Zahlung nur den Status `APPROVED`, `PENDING` oder `COMPLETED`. PayPal meldet jedoch einen anderen Status. Der häufigste Grund dafür ist, dass der Kunde die Zahlung im PayPal-Fenster nie final abgeschlossen hat, beispielsweise weil er das Fenster geschlossen oder zurücknavigiert hat. Die Order steht bei PayPal dann noch auf `CREATED`, während der Shop trotzdem eine Statusabfrage anstößt. Der Teil vor dem Doppelpunkt, `Failed to load payment status for order`, ist dabei keine eigenständige Ursache, sondern eine Rahmenmeldung, die in allen Fällen angezeigt wird, in denen der Shop den Zahlungsstatus nicht abrufen konnte. Die eigentliche Ursache steht dahinter. Der Zusatz in Klammern sagt Ihnen, um welchen Zahlungsablauf es geht: | **Zusatz** | **Zahlungsablauf** | **Akzeptierte PayPal-Status** | | -------------- | ----------------------------- | ------------------------------------------------------ | | `(regular)` | Reguläre PayPal-Zahlung | `APPROVED`, `PENDING`, `COMPLETED` | | `(cc)` | Kreditkarte | `APPROVED`, `PENDING`, `CREATED` | | `(invoice)` | Rechnungskauf | `APPROVED`, `PENDING`, `COMPLETED`, `PENDING_APPROVAL` | | `(apm)` | Alternative Zahlungsart | `APPROVED`, `PENDING`, `COMPLETED` | | `(no payment)` | Zahlungsart nicht ermittelbar | `APPROVED`, `PENDING` | #### Vorgehen Vereinzeltes Aufkommen kann als normales Kundenverhalten (beispielsweise durch eine abgebrochene Zahlung im PayPal-Fenster) angesehen werden und ist kein Fehler im Shop.  Suchen Sie im Log nach der Nachrichten-ID `paypalCheckoutService.checkoutValidateOrderDetails`. Diese Meldung steht auf Log-Level "Info" und enthält die vollständige Antwort von PayPal einschließlich des tatsächlichen `status`-Werts. Daran sehen Sie, in welchem Zustand die Order bei PayPal hängt. Legen Sie die Log-Gruppe deshalb so an, dass sie das Level Info mit einschließt. Sonst fehlt Ihnen genau die Meldung, die die Antwort enthält. Wenn die Meldung gehäuft und reproduzierbar auftritt, prüfen Sie bitte die Integration des PayPal-Buttons im Checkout-Template. Konkret ist zu prüfen, ob der Aufruf mit `wsPaymentStatus=refresh` bereits ausgelöst wird, bevor der Kunde die Freigabe bei PayPal abgeschlossen hat. Das ist das typische Symptom bei selbst angepassten PayPal-Button-Handlern, siehe [Praxisbeispiele - Verknüpfung mit dem Zahlungsanbieter](/verknuepfung-zahlungsanbieter). Wenn der Status weder `APPROVED` noch `PENDING` oder `COMPLETED` ist, obwohl der Kunde den Checkout augenscheinlich nochmal durchlaufen hat, melden Sie den Fall mit der Bestellnummer an WEBSALE. *** ### `Internal error while validating order: Payment is in invalid state setting payment to error: checkoutCapture: response status is not valid (regular)` Nachrichten-ID: `paypalCheckout.handleHookValidationError` ####
    Symptom Ein von PayPal dem Shop im Hintergrund gemeldetes Ereignis wird nicht verarbeitet. Der Zahlungsstatus der Bestellung bleibt unverändert. Der Shop antwortet PayPal mit einem Fehler, woraufhin PayPal dasselbe Ereignis über Tage hinweg erneut zustellt. Bei dauerhaftem Auftreten dieses Problems kann PayPal den Webhook-Endpunkt des Shops abschalten. #### Ursache PayPal benachrichtigt den Shop serverseitig über verschiedene Ereignisse zu einer Bestellung, zum Beispiel "Zahlung genehmigt", "Betrag eingezogen" oder "Zahlung abgelehnt". Zur Absicherung fragt der Shop bei jedem eingehenden Webhook zusätzlich den aktuellen Bestellstatus direkt bei PayPal ab und prüft ihn. Bei einer regulären PayPal-Zahlung akzeptiert diese Prüfung nur die Status `APPROVED` , `PENDING` und `COMPLETED`. WIrd ein anderer Status gemeldet, beispielsweise `CREATED` , `VOIDED` oder `PAYER_ACTION_REQUIRED` , wird die Verarbeitung des Webhooks mit dieser Meldung abgebrochen. Dies ist die Webhook-Variante eines verwandten Problems. Kommt der Kunde selbst per Browser-Weiterleitung in den Shop zurück und der Shop fragt dabei den Status ab, entsteht die fast wortgleiche Meldung [Failed to load payment status for order:Payment is in invalid state...](#failed-to-load-payment-status-for-orderpayment-is-in-invalid-state-setting-payment-to-error-checkoutcapture-response-status-is-not-valid-regular). Beide laufen über dieselbe Prüffunktion und unterscheiden sich nur im Auslöser: einmal die Rückkehr des Kunden, einmal die serverseitige Benachrichtigung durch PayPal. **Wichtig:**
    Die Statusprüfung erfolgt vor der Auswertung des Ereignistyps. Die Ereignisse `PAYMENT.CAPTURE.DENIED` (Zahlung abgelehnt) und `CHECKOUT.PAYMENT-APPROVAL.REVERSED` (Genehmigung zurückgezogen) würden die Bestellung eigentlich sauber auf "abgelehnt" setzen. Bricht die vorgelagerte Statusprüfung jedoch ab, wird der Ereignistyp nie ausgewertet und die Bestellung bleibt in ihrem bisherigen Zahlungsstatus stehen. Dies ist keine Frage der Konfiguration, sondern eine Lücke im Zusammenspiel der beiden Prüfungen.
    #### Vorgehen Suchen Sie im Log kurz davor nach der Nachrichten-ID `paypalCheckoutService.checkoutValidateOrderDetails`. Diese Meldung steht auf Log-Level "Info" und enthält die vollständige Antwort von PayPal einschließlich des tatsächlichen `status`-Werts. Suchen Sie direkt davor nach der Nachrichten-ID `paypalCheckout.validateWebhookPayload`. Diese Meldung steht ebenfalls auf Log-Level "Info" und enthält den vollständigen Webhook-Inhalt von PayPal. Darin finden Sie im Feld `event_type` das auslösende Ereignis. Legen Sie die Log-Gruppe deshalb so an, dass sie das Level Info mit einschließt. Sonst fehlen Ihnen beide Meldungen. Aus dem Ereignistyp und dem PayPal-Status ergibt sich, was zu tun ist. | **Gefundener Wert** | **Bedeutung** | **Maßnahme** | | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `event_type` ist `PAYMENT.CAPTURE.DENIED` oder `CHECKOUT.PAYMENT-APPROVAL.REVERSED` | Die Zahlung wurde abgelehnt oder die Genehmigung wurde zurückgezogen. Das ist inhaltlich kein Fehler des Shops, sondern eine echte Zahlungsablehnung. | Bestellstatus im Admin-Interface prüfen. Bleibt die Bestellung in einem offenen Zahlungsstatus hängen, setzen Sie sie manuell auf storniert oder fehlgeschlagen. | | `status` ist `VOIDED` oder `PAYER_ACTION_REQUIRED` | Die PayPal-Bestellung ist verfallen oder wartet auf eine Kundenaktion, die nie erfolgt ist. | Kein Konfigurationsfehler. Die Bestellung ist für den Kunden nicht mehr abschließbar. | | `status` ist `CREATED` | Der Kunde hat die Zahlung im PayPal-Fenster nie freigegeben. | Kein Handlungsbedarf, solange es Einzelfälle bleiben. | Vereinzeltes Aufkommen ist angesichts dieser Fälle normal. Tritt der Fehler gehäuft und immer mit demselben `event_type` auf, insbesondere mit `PAYMENT.CAPTURE.DENIED` oder `CHECKOUT.PAYMENT-APPROVAL.REVERSED`, melden Sie das bitte an WEBSALE. Zu prüfen ist dann, ob die Reihenfolge von Statusprüfung und Ereignisauswertung angepasst werden sollte, damit diese beiden Ereignisse wie vorgesehen als abgelehnte Zahlung durchlaufen. Bleibt die Ursache unklar, melden Sie den Fall bei WEBSALE unter Angabe der Bestellnummer sowie der in Schritt 1 und 2 gefundenen Werte. *** ### `Failed to load payment status for order:getOrderDetails: Failed to communicate with paypal` Nachrichten-ID: `paymentCheckBeforeRoute.clearerStatusUpdateFailed` ####
    Symptom Der Zahlungsstatus einer Bestellung wird nicht aktualisiert. Die Bestellung behält daher den Status, den sie vor dem Abgleich hatte. #### Ursache Der Shop wollte den Zahlungsstatus einer Bestellung bei PayPal abfragen, beispielsweise, wenn der Kunde von PayPal in den Shop zurückgeleitet wurde oder ein automatischer Statusabgleich lief. Der Aufruf an PayPal ist jedoch fehlgeschlagen und der Shop hat keine verwertbare Antwort erhalten. Die konkrete Ursache, beispielsweise eine Zeitüberschreitung, ungültige Zugangsdaten oder eine Störung bei PayPal, ist in dieser Meldung nicht angegeben. Es gibt eine zweite Variante mit dem Zusatz "`result was not a valid JSON`". In diesem Fall hat PayPal zwar geantwortet, aber nicht in einem für den Shop auswertbaren Format. #### Vorgehen Vereinzeltes Vorkommen, das sich über die Zeit verteilt, ist meist auf ein vorübergehendes Netzwerk- oder PayPal-Problem zurückzuführen. Hier besteht kein Handlungsbedarf. Kontrollieren Sie die Client-ID, das Secret und den Betriebsmodus. Der Modus (`sandbox` oder `live`) muss zu den hinterlegten Zugangsdaten passen. Prüfen Sie zunächst, ob alle Subshops oder nur einzelne betroffen sind. Sind nur einzelne betroffen, deutet das auf eine subshop-spezifische Fehlkonfiguration hin, denn Konfigurationsknoten lassen sich pro Subshop überschreiben. Wenn die Konfiguration korrekt aussieht, der Fehler aber weiterhin dauerhaft auftritt, melden Sie das bitte an WEBSALE. Dahinter kann eine Netzwerk- oder Firewall-Blockade in Richtung PayPal stehen oder ein Problem auf PayPal-Seite, das sich über die Shop-Konfiguration nicht lösen lässt. *** ### `Error setting up the connection to paypal api (Http: 404)` Nachrichten-ID: `paypalCheckoutService.callApiHttpError` ####
    Symptom Ein Vorgang, in den PayPal involviert ist, wird nicht abgeschlossen. Je nach betroffenem Aufruf wird entweder eine Zahlung nicht eingezogen oder ein Zahlungsstatus nicht aktualisiert. Bei den Fehlercodes `401` und `403` betrifft das sämtliche PayPal-Zahlungen im Shop, bei `404` in der Regel nur einzelne Bestellungen. #### Ursache PayPal hat einen Aufruf der PayPal-REST-API, beispielsweise eine Statusabfrage oder einen Zahlungseinzug, mit einem Fehlercode beantwortet. Diese Meldung erscheint bei jedem HTTP-Code, der nicht erfolgreich ist. Der Code in Klammern entscheidet über die Bedeutung. | **HTTP-Code** | **Bedeutung** | **Typische Ursache** | | ------------- | -------------------------------- | ------------------------------------------------------------ | | `400` | Ungültige Anfrage | Fehlerhafte Daten in der Anfrage an PayPal. | | `401` | Authentifizierung fehlgeschlagen | Client-ID oder Secret stimmen nicht. | | `403` | Nicht berechtigt | Die Zugangsdaten haben für diesen Aufruf keine Berechtigung. | | `404` | Nicht gefunden | PayPal kennt die angefragte Order-ID nicht (mehr). | Bei `404` sind zwei Ursachen üblich. Entweder existiert die PayPal-Bestellung nicht mehr, weil der Kunde sie nie abgeschlossen hat und sie auf PayPal-Seite verfallen ist. Oder die Sandbox- und die Live-Umgebung passen nicht zusammen, beispielsweise weil Live-Zugangsdaten hinterlegt sind, die Order aber noch unter Sandbox angelegt wurde. Direkt danach steht im Log die Rohantwort von PayPal unter der Nachrichten-ID `paypalCheckoutService.callApiHttpErrorResult`, beispielsweise: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Result: {"name":"RESOURCE_NOT_FOUND","details":[{"issue":"INVALID_RESOURCE_ID"}]} ``` `RESOURCE_NOT_FOUND` und `INVALID_RESOURCE_ID` bestätigen dies. Die angefragte Order-ID existiert bei PayPal nicht mehr. Es gibt eine ähnliche Fehlermeldung beim Abholen des Zugriffstokens: "`Error setting up the connection to Paypal API for Access Token (Http: ...)`". Tritt diese auf, sind die Zugangsdaten grundsätzlich ungültig, unabhängig von einer einzelnen Bestellung. #### Vorgehen In der Meldung selbst ist keine Bestellnummer enthalten. Suchen Sie im selben Zeitfenster nach der Nachrichten-ID `paypalCheckoutService.callApiErrorResponse`. Diese Meldung steht auf Log-Level `Info` und enthält die Bestellnummer, die Transaktions-ID, die gesendete Anfrage und die vollständige Antwort von PayPal. Client-ID, Secret und der Betriebsmodus müssen zusammenpassen. Dies ist besonders relevant, wenn kürzlich zwischen Sandbox und Live gewechselt wurde. Wenn die Bestellung bereits mehrere Stunden zurückliegt, ist die PayPal-Bestellung regulär verfallen. Das ist kein Konfigurationsfehler. Die Bestellung lässt sich für den Kunden ohnehin nicht mehr abschließen. Wenn der Fehler bei aktuellen Bestellungen auftritt, melden Sie ihn bitte unter Angabe der Bestellnummer aus Schritt 1 bei WEBSALE. *** ## Computop Hosted ### `payment method invalid, not defined in computopHosted config` Nachrichten-ID: `computopHosted.getComputopHostedConfigPaymentMethodInvalid` ####
    Symptom Der Kunde wählt im Checkout eine bestimmte Zahlungsart aus, doch statt zur Computop-Bezahlseite weitergeleitet zu werden, bricht die Zahlung ab. Betroffen ist genau die Zahlungsart, deren ID in der Meldung angegeben ist. #### Ursache Die gewählte Zahlungsart soll über Computop Hosted abgewickelt werden. Das Shopsystem sucht dazu im Konfigurationsknoten `payment.computopHosted` nach dem Eintrag mit dieser Zahlungsart-ID, kann ihn jedoch nicht finden. Daraufhin bricht die Zahlung kontrolliert ab. Dies ist kein technischer Fehler, sondern eine fehlende oder falsche Zuordnung in der Konfiguration. Die betroffene Zahlungsart-ID steht ohne Leerzeichen direkt hinter dem Doppelpunkt der Meldung. #### Vorgehen Die Zahlungsart-ID können Sie der Meldung entnehmen. Den Subshop entnehmen Sie dem Log-Eintrag, denn jeder Eintrag ist einem Subshop zugeordnet. Öffnen Sie den Knoten `payment.computopHosted` und prüfen Sie für den betroffenen Subshop, ob ein Eintrag mit dieser ID existiert. Wenn die ID unter `payment.payment` aktiv ist, aber nicht unter `payment.computopHosted` hinterlegt ist, müssen Sie sie dort ergänzen. Konfigurationsknoten lassen sich pro Subshop überschreiben. Prüfen Sie deshalb jeden betroffenen Subshop einzeln. Wenn die ID nicht mehr existiert, weil sie umbenannt oder entfernt wurde, prüfen Sie Ihre Templates auf eine fest eingetragene alte Zahlungsart-ID und stellen Sie auf eine dynamische Referenz um.  Führen Sie im betroffenen Subshop eine Testtransaktion durch und beobachten Sie dabei die Log-Gruppe. Wenn die Meldung trotz korrekter Konfiguration bestehen bleibt, sehen Sie sich das Muster an. Viele verschiedene, wechselnde Zahlungsart-IDs stammen erfahrungsgemäß eher aus veralteten Sitzungen oder von automatisierten Zugriffen als aus einer Fehlkonfiguration. # Gutscheine Source: https://dokumentation.websale.de/admin-interface/marketing/gutscheine Gutscheine im Admin-Interface anlegen und verwalten: Gutschein-Chargen erstellen, Kaufgutscheinvorlagen für verkaufte Gutscheine anlegen und Gutscheinvorlagen wiederverwenden. Gutscheine werden im Admin-Interface unter dem Dienst angelegt und verwaltet. Auf dieser Seite wird beschrieben, wie ein Gutschein erstellt wird, welche Einstellungen dabei zur Verfügung stehen und welche Unterschiede es bei Kauf- und Werbegutscheinen gibt. Die Seite [Praxisbeispiele Gutscheine](/gutscheine) beschreibt unter anderem, wie Gutscheine ins Template eingebunden werden können. Wie ein Produkt zu einem verkaufbaren Gutschein wird, ist unter [Kaufgutschein-Produkt anlegen](/admin-interface/katalog/produkte/kaufgutschein-produkt) beschrieben. *** ## Aufruf des Dienstes Den Dienst erreichen Sie über folgende URL: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/vouchers ``` *** ## Gutschein und Gutschein-Charge Ein Gutschein ist der Code, den ein Kunde im Shop eilösen kann. Eine Gutschein-Charge regelt alles um den Gutschein herum, beispielsweise Wert, Währung, Gültigkeitszeitraum und Einlösebedingungen. Jeder Gutschein gehört zu genau einer Charge und erbt deren Einstellungen.

    Beim Anlegen eines Gutscheines entsteht daher immer eine Charge und, je nach Vorgangsweise, die Gutscheine darin.

    Die Charge wird über ihre ID angesprochen. Diese ID ist die einzige Angabe, mit der anderen Stellen im System auf eine Charge verweisen, beispielsweise ein Kaufgutschein-Produkt. Die Chargen-ID ist nicht die Bezeichnung der Charge. Wenn beim Anlegen keine ID eingetragen wird, vergibt das System eine fortlaufende Nummer wie beispielsweise "122". *** ## Die Bereiche der Gutscheinverwaltung Der Dienst gliedert sich in drei Reiter mit folgenden Inhalten: | Reiter | Inhalt | Wofür | | ------------------------ | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | **Gutscheine** | Alle Gutschein-Chargen mit Bezeichnung, Chargen-ID, Anzahl, Gutscheinwert und Label | Übersicht der vorhandenen Gutschein-Chargen | | **Kaufgutscheinvorlage** | Vorlagen, aus denen beim Kauf eines Kaufgutschein-Produkts Gutscheine entstehen | Verkaufbare Gutscheine, siehe [Kaufgutscheinvorlage anlegen](#kaufgutscheinvorlage-anlegen). | | **Gutscheinvorlagen** | Wiederverwendbare Vorbelegungen der Eingabemaske | Wiederkehrende Aktionen schneller anlegen | Gutscheine Drei Wege In der Liste der Chargen ist die Spalte "Anzahl" das schnellste Erkennungsmerkmal. Steht dort eine Zahl größer als null, enthält die Charge fertige Gutscheincodes. Steht dort `0`, gehört die Charge zu einer Kaufgutscheinvorlage, deren Codes erst mit einer Bestellung entstehen. *** ## Gutscheinarten Beim Anlegen wird unter "Art des Gutscheins" zwischen zwei Arten unterschieden. Die getroffene Auswahl entscheidet darüber, auf welche Positionen der Gutschein wirkt. | Art | Wirkung | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Werbegutschein** | Wirkt nur auf Produkte, bei denen das Feld "Zulässig für Wertgutscheine" gesetzt ist. Damit lassen sich Warengruppen von Rabattaktionen ausnehmen. | | **Kaufgutschein** | Wirkt als Zahlungsmittel auf alle Positionen und übergeht diese Einschränkung. Diese Einstellung gilt für verkaufte Gutscheine und Geschenkgutscheine. | *** ## Eine Gutschein-Charge anlegen Über "+ Neuer Gutschein" öffnet sich eine Maske mit mehreren Abschnitten. Sie wird von oben nach unten ausgefüllt, die Abschnitte sind zugleich als Reiter erreichbar. ### Vorlage Zunächst wird eine Gutscheinvorlage ausgewählt oder die Option "Ohne Vorlage" gewählt. Erst nach dieser Auswahl werden die weiteren Abschnitte angezeigt. Eine gewählte Vorlage belegt die entsprechenden Felder und sperrt die übrigen. ### Allgemeine Einstellungen Gutschein Neuer Gutschein Anlegen | Feld | Bedeutung | | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Aktiv** | Steuert, ob die Gutscheine der Charge eingelöst werden können. | | **Bezeichnung** | Pflichtfeld. Name der Charge. Leerzeichen sind nicht erlaubt, das Feld wird sonst als fehlerhaft markiert. | | **Chargen-ID** | Frei vergebbare ID der Charge. Bleibt das Feld leer, vergibt das System eine fortlaufende Nummer. Eine bereits vergebene ID wird abgelehnt. | | **Gutscheincode manuell festlegen** | Erlaubt die Eingabe eines eigenen Codes. Sinnvoll nur, wenn genau ein Gutschein erzeugt wird. | | **Gutscheincode** | Der manuell vergebene Code. Ohne den Schalter darüber erzeugt das System die Codes selbst. | | **Anzahl** | Anzahl der zu erzeugenden Gutscheincodes. Für Kaufgutscheinvorlagen ohne Bedeutung, siehe [Kaufgutscheinvorlage anlegen](#kaufgutscheinvorlage-anlegen). | | **Maximale Anzahl der Einlösungen festlegen** | Begrenzt, wie oft ein Gutschein insgesamt eingelöst werden kann. | | **Gutschein von verschiedenen Kunden einlösbar** | Erlaubt die Einlösung durch mehrere Kunden. | | **Maximale Anzahl der Einlösungen pro Kunde festlegen** | Begrenzt die Einlösungen je Kunde. | | **Art des Gutscheins** | Pflichtfeld. Werbegutschein oder Kaufgutschein, siehe [Gutscheinarten](#gutscheinarten). | | **Labels** | Stichworte zur Charge. Über Labels wird gesteuert, welche Gutscheine sich in einer Bestellung miteinander kombinieren lassen. Ohne Eingabe setzt der Shop das Label selbst. | ### Gutscheinwert Die Verrechnungsart legt fest, ob der Gutschein einen absoluten Betrag abzieht, einen prozentualen Rabatt gewährt oder einen prozentualen Rabatt bis zu einem Höchstbetrag gewährt. Darunter steht für jede Währung eine Zeile mit Währung, Mehrwertsteuer-ID, Gutscheinwert und Mindestbestellwert. Über "Weitere Währung hinzufügen" können weitere Zeilen hinzugefügt werden. Ein Gutschein wirkt nur in Währungen, für die eine Zeile existiert. Der hier eingetragene Mindestbestellwert gilt ausschließlich als Einlösebedingung für diesen Gutschein. Er ist kein globaler Mindestbestellwert für den Warenkorb oder Checkout. Wie mehrere Mindestbestellwerte bei gleichzeitig eingelösten Gutscheinen verrechnet werden, steuern die Optionen `minOrderValueCalculation` und `minOrderValueIgnoreVoucherReduction` unter [Checkout-Bestellablauf](/konfiguration/checkout-bestellablauf). In diesem Abschnitt befinden sich noch zwei weitere Einstellungen: * **Restbetrag**: Bei "Restbetrag wiederverwendbar" bleibt ein nicht ausgeschöpfter Betrag erhalten und kann später erneut eingelöst werden. Bei "Restbetrag verfällt" ist der Gutschein nach der ersten Einlösung verbraucht. * **kostenloser Versand**: Setzt bei Einlösung die Versandkosten auf null. Eine anteilige Ermäßigung der Versandkosten (z.B. Halbierung) ist über einen Gutschein nicht vorgesehen; die Option wirkt ausschließlich als "voll kostenfrei" oder gar nicht. ### Weitere Abschnitte | Abschnitt | Inhalt | | ------------------------------------------------ | -------------------------------------------------------------------------- | | **Subshops** | In welchen Subshops die Gutscheine gelten. | | **Zeitraum der Gültigkeit** | Beginn ab Generierung oder ab einem Datum, Ende offen oder zu einem Datum. | | **Zielgruppe** | Einschränkung auf Neukunden, Bestandskunden oder einzelne Kunden. | | **Produkte automatisch in den Warenkorb legen** | Produkte, die beim Einlösen automatisch hinzugefügt werden. | | **Einlösebedingungen - Kategorien und Produkte** | Einschränkung der Gültigkeit auf bestimmte Kategorien oder Produkte. | ### Speichern Der Button "Gutschein generieren" ist ein geteilter Button. Der Pfeil daneben öffnet drei weitere Optionen. Die Auswahl entscheidet darüber, was tatsächlich generiert wird: Button Gutschein Generieren Geoeffnet | Aktion | Ergebnis | | ------------------------------------------------ | ------------------------------------------------------------------------------- | | Gutschein generieren | Erzeugt die eingestellte Anzahl fertiger Gutscheincodes in einer neuen Charge. | | Gutschein generieren und schließen | Wie oben, schließt danach die Maske. | | Gutschein generieren und als Vorlage speichern | Wie oben, sichert die Eingaben zusätzlich als Gutscheinvorlage. | | **Gutschein als Kaufgutscheinvorlage speichern** | Erzeugt keine Codes, sondern eine Kaufgutscheinvorlage samt zugehöriger Charge. | *** ## Kaufgutscheinvorlage anlegen Eine Kaufgutscheinvorlage ist die Grundlage für Gutscheine, die im Shop verkauft werden. Sie enthält selbst keine Codes. Diese entstehen erst, wenn ein Kunde ein [Kaufgutschein-Produkt](/admin-interface/katalog/produkte/kaufgutschein-produkt) bestellt, und zwar einer je bestellter Einheit. Die Vorlage wird in derselben Maske angelegt wie eine gewöhnliche Charge: Die Bezeichnung wird zur Kaufgutscheinvorlagen-ID. Die Chargen-ID sollte manuell und sprechend vergeben werden, beispielsweise `geschenkgutschein`, denn genau dieser Wert wird später am Produkt eingetragen. Bleibt das Feld leer, muss die erzeugte Nummer hinterher in der Liste gesucht werden. Verkaufte Gutscheine sind ein Zahlungsmittel und sollen unabhängig davon wirken, ob einzelne Produkte für Wertgutscheine freigegeben sind. Die Verrechnungsart ist auf "absolut" eingestellt, der Gutscheinwert bleibt bei `0`. Den tatsächlichen Wert setzt der Preis des verkauften Produkts. Die Charge sollte nur eine Währung führen. Beim Restbetrag ist "Restbetrag wiederverwendbar" die richtige Wahl, sonst verfällt bei einer Teileinlösung der Rest des gekauften Guthabens. Im Menü neben "Gutschein generieren" den Eintrag "**Gutschein als Kaufgutscheinvorlage speichern"** wählen. Der Hauptknopf würde stattdessen fertige Gutscheincodes anlegen, die ein Kaufgutschein-Produkt nicht verwenden kann. Nach dem Speichern steht der Eintrag im Reiter Kaufgutscheinvorlage mit Vorlagen-ID und Chargen-ID bereit. Dieselbe Charge erscheint zusätzlich im Reiter Gutscheine mit der Anzahl `0`. Kaufgutscheinvorlage Erstellt Der nächste Schritt zur Erstellung eines Kaufgutscheins ist die Produktseite → [Kaufgutschein-Produkt anlegen](/admin-interface/katalog/produkte/kaufgutschein-produkt). *** ## Gutscheinvorlagen Mit einer Gutscheinvorlage werden die Eingaben der Maske gespeichert, sodass wiederkehrende Aktionen nicht jedes Mal neu ausgefüllt werden müssen. Sie wird über den Eintrag "Gutschein generieren und als Vorlage speichern" angelegt und steht anschließend im Abschnitt "Vorlage" oben zur Auswahl. Vorlagen wirken nur beim Anlegen. Eine geänderte oder gelöschte Vorlage hat keinen Einfluss auf bereits erzeugte Chargen und Gutscheine. *** ## Anzeige im Shop Wie Gutscheine im Shop erscheinen, bestimmt das Template. Im Admin-Interface gibt es dafür keine Einstellungen. * Das Eingabefeld für den Gutscheincode, die Liste der eingelösten Gutscheine und die Fehlertexte werden im Template ausgegeben. Beispiele dazu stehen in den [Praxisbeispielen Gutscheine](/gutscheine). * Welche Daten dabei zur Verfügung stehen, beschreibt das Modul [\$wsVoucher](/frontend/referenz/module/wsvoucher). * Verkaufte Gutscheine erscheinen nicht über dieses Modul, sondern am Warenkorbartikel, siehe [Kaufgutschein-Produkt anlegen](/admin-interface/katalog/produkte/kaufgutschein-produkt). *** ## Begriffe und technische Namen | Konzept | Admin-Interface | Schnittstelle | | -------------------------------- | -------------------- | -------------------- | | Gruppe von Gutscheinen | Gutschein-Charge | `vouchers/charges` | | Einzelner Code | Gutschein | `vouchers` | | Vorlage für verkaufte Gutscheine | Kaufgutscheinvorlage | `vouchers/templates` | | Vorbelegung der Eingabemaske | Gutscheinvorlage | `vouchers/presets` | | Verweis auf eine Charge | Chargen-ID | `chargeId` | *** ## Wegweiser * [Kaufgutschein-Produkt anlegen](/admin-interface/katalog/produkte/kaufgutschein-produkt) beschreibt den zweiten Teil des Ablaufs. * [API-Referenz Gutscheine](/schnittstellen/admin-interface-api/api-referenz-gutscheine) beschreibt dieselben Objekte über die Schnittstelle. * [Praxisbeispiele Gutscheine](/gutscheine) zeigt das Einlösen im Shop-Template. * [checkout - Bestellablauf](/konfiguration/checkout-bestellablauf) beschreibt die Einstellungen zum Einlösen im Bestellablauf. # Textbausteine Source: https://dokumentation.websale.de/admin-interface/templates-und-content/textbausteine Textbausteine sind der zentrale Ort, an dem alle Texte gepflegt werden, die der Shop an verschiedenen Stellen anzeigt. Ein Textbaustein besteht aus einer Bezeichnung und einem Text. Im Template wird nur die Bezeichnung eingebunden, nicht der Text selbst. Dadurch wird der Text an einer Stelle geändert und die Änderung wirkt sich überall dort aus, wo der Baustein vorkommt. Typische Beispiele hierfür sind Buttons, Hinweise, Fehlermeldungen und rechtliche Texte. | Bezeichnung | Text (Deutsch) | Text (Englisch) | | -------------------------------------- | -------------------------- | ----------------------- | | `shop.basket.addButton` | In den Warenkorb | Add to cart | | `shop.checkout.shippingNote` | Versandkostenfrei ab 50 €. | Free shipping from €50. | | `ws.error.addressValidation.minLength` | Die Eingabe ist zu kurz. | The entry is too short. | Die Bezeichnung ist der technische Name, unter dem das Template oder eine Konfiguration den Text anfordert. Der Text ist das, was der Kunde im Shop liest. ## Sprachen sind die Grundlage Textbausteine existieren immer im Zusammenhang mit einer Sprache. Drei Punkte gehören dafür zusammen: * **Jede Sprache wird einmal im Shop angelegt** – als eigenständiges Objekt in der Konfiguration, nicht im Textbaustein-Dienst. * **Jeder Subshop hat genau eine Sprache.** Welcher Text ein Kunde sieht, hängt davon ab, welchen Subshop er aufruft: Der Subshop bestimmt die Sprache, die Sprache bestimmt den Text. * **Ein Textbaustein hat je Sprache eine eigene Fassung.** Die Bezeichnung ist immer dieselbe, der Text unterscheidet sich. Solange keine Sprache angelegt und keinem Subshop zugewiesen ist, gibt es auch keine Texte, die der Shop ausgeben könnte. Wie Sprachen angelegt, zugewiesen und miteinander verkettet werden, steht unter [Sprachen anlegen und zuweisen](#sprachen-anlegen-und-zuweisen). ## Textpflege Gepflegt werden die Texte im Admin Interface unter dem Dienst , erreichbar unter: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/text ``` Die Rechte werden je Dienst vergeben, unter . Für die Textbausteine gibt es fünf davon: | Recht | Erlaubt | | --------------- | --------------------------------------------------------------------- | | **Ansehen** | Die Übersicht öffnen, Texte ansehen, suchen und filtern, exportieren. | | **Bearbeiten** | Bestehende Texte ändern. | | **Erstellen** | Neue Textbausteine anlegen und bestehende duplizieren. | | **Löschen** | Textbausteine oder einzelne Sprachen eines Textbausteins entfernen. | | **Publizieren** | Änderungen im Shop wirksam machen. | | **Alle** | Alle genannten Rechte sind vergeben. | Ein Import benötigt beispielsweise die Rechte Anlegen und Bearbeiten. Die Rechte gelten immer für den ganzen Dienst, nicht für einzelne Sprachen. Wer Texte lesen darf, sieht alle Sprachen; wer bearbeiten darf, kann alle Sprachen ändern. Eine Beschränkung auf einzelne Sprachen – etwa für externe Übersetzer – ist derzeit nicht möglich. Für einen Übersetzungsauftrag ist deshalb der [Export einer einzelnen Sprache](#import-und-export) der geeignete Weg. ## Die Übersicht Textblocks Lang3 Der Dienst zeigt eine Tabelle, in der jede Zeile einem Textbaustein und jede weitere Spalte einer Sprache entspricht. Bis zu drei Sprachen lassen sich gleichzeitig nebeneinander vergleichen und direkt in der Tabelle bearbeiten. Welche Sprachen als Spalten erscheinen, wählen Sie selbst; per Drag & Drop lassen sie sich umsortieren. Die linke Sprachspalte ist die Fokussprache. Sie ist hervorgehoben, und die Verfügbarkeitsfilter beziehen sich immer auf sie – nicht auf die anderen sichtbaren Spalten. Eine Sprache nach ganz links zu ziehen, macht sie zur Fokussprache. ### Der Verfügbarkeitsstatus Der Verfügbarkeitsstatus gibt Auskunft über den Status eines Textbausteins in einer bestimmten Sprache. Es gibt drei Ausprägungen, die in den Zellen farblich hinterlegt sind: * **grün = gepflegt** – es liegt ein Text vor. * **gelb = leer** – es gibt zwar einen Eintrag für diese Sprache, aber ohne Inhalt. * **rot = nicht vorhanden** – für diese Sprache existiert noch gar kein Eintrag. So lässt sich auf einen Blick erkennen, wo in einer Sprache noch Lücken bestehen. ### Suchen und Filtern Da mit der Zeit viele Textbausteine über mehrere Sprachen hinweg entstehen, lässt sich die Übersicht durchsuchen und filtern. * **Suche** – über Bezeichnung und Text. * **Verfügbarkeit** – genau die drei Farben aus der Tabelle. Sie können also gezielt alle Bausteine anzeigen, die in der Fokussprache leer oder nicht vorhanden sind, und so die Lücken einer Sprache abarbeiten. Mehrere Zustände lassen sich kombinieren; angezeigt wird dann, was einen der gewählten Zustände hat. * **Typ** – System-Textbausteine oder eigene Textbausteine. * **Verwendung** – ob der Baustein in einem Template referenziert wird. Der Bezug lässt sich auf einen einzelnen Subshop einschränken, weil die Templates verschiedener Subshops unterschiedliche Bausteine nutzen können. Wie dieser Stand entsteht, steht unter [Wirkung im Shop](#wirkung-im-shop). * **Namensraum** – eine Baumansicht über die Punkt-Ebenen der Bezeichnungen. Der Baum ist nicht vorgegeben, sondern entsteht aus den Bezeichnungen, die tatsächlich im Shop existieren: Aus `shop.checkout.button.label` werden die Ebenen `shop`, `shop.checkout` und `shop.checkout.button`. Wie brauchbar dieser Filter ist, hängt also davon ab, wie konsequent die Bezeichnungen benannt sind. Wer neue Bausteine nach einem festen Schema benennt – etwa mit einem Präfix je Shop-Bereich –, kann später gezielt einen Bereich herausfiltern. ## System- und eigene Textbausteine ### System-Textbausteine System-Textbausteine werden vom Shop **automatisch erzeugt**. Sie entstehen aus Konfigurationsfeldern, die vom System vorgegeben und nicht editierbar sind – in aller Regel Fehlertexte. Ihre Bezeichnung beginnt mit `ws.error.` Solche Felder gibt es nicht nur bei den [actions](/konfiguration/actions-fehlertexte-e-mails), sondern auch in anderen Bereichen wie Checkout, Benutzerkonten und externen Datenquellen. Das Feld in der Konfiguration trägt dabei nicht den Fehlertext, sondern nur die Bezeichnung des Textbausteins; gepflegt wird der Text ausschließlich hier im Textbaustein-Dienst. Bei Shop-Updates kommen laufend neue System-Textbausteine dazu, sobald neue Konfigurationsbereiche oder Erweiterungen ausgeliefert werden. Diese werden in der Regel mit deutschem Text ausgeliefert, und zwar nur in der Hauptsprache des jeweiligen Subshops. Texte für weitere Sprachen müssen Sie selbst hinterlegen. Nach einem Update lohnt sich deshalb ein Blick auf den Verfügbarkeitsfilter: Fokussprache auf die betreffende Sprache setzen und nach *nicht vorhanden* filtern zeigt genau die neu dazugekommenen Lücken. Was Sie mit System-Textbausteinen tun dürfen und was nicht: * **Der Text ist frei änderbar** – in jeder Sprache, ohne Einschränkung. Sie können also die Formulierung einer Fehlermeldung vollständig an Ihr Wording anpassen. * **Die Bezeichnung ist gesperrt.** System-Textbausteine lassen sich weder umbenennen noch löschen – auch nicht sprachweise. Der Shop verweist an fester Stelle auf diese Bezeichnung; ohne sie stünde dort kein Text. ### Eigene Textbausteine Bei der Bereitstellung eines Shops wird bereits ein großer Satz eigener, frei änderbarer Textbausteine ausgeliefert. Die Templates selbst enthalten **keine** Texte – sämtliche Texte liegen in Textbausteinen. Dadurch lässt sich das gesamte Wording eines Shops über diesen Dienst anpassen, ohne ein Template zu berühren. Darüber hinaus können Sie beliebig viele eigene Textbausteine anlegen, etwa für individuelle Hinweise oder Inhalte, die nur in diesem Shop gebraucht werden. Diese lassen sich vollständig anlegen, bearbeiten, umbenennen und wieder löschen. **Erlaubte Zeichen in der Bezeichnung:** Buchstaben `a–z` und `A–Z`, Ziffern `0–9`, Punkt `.` und Unterstrich `_`. Nicht erlaubt sind Leerzeichen, Bindestriche, Umlaute und alle übrigen Sonderzeichen. Der Punkt ist dabei mehr als ein Trennzeichen: Er bildet die Ebenen des Namensraum-Filters (siehe [Suchen und Filtern](#suchen-und-filtern)). Das Präfix `ws.` ist für System-Textbausteine reserviert und lässt sich nicht vergeben. Einen Textbaustein anzulegen genügt nicht, damit er im Shop erscheint. Die Bezeichnung muss zusätzlich an der gewünschten Stelle im Template oder in einer Konfiguration eingesetzt werden. Umgekehrt gilt beim Löschen dasselbe: Entfernen Sie den Baustein erst aus Template und Konfiguration und löschen Sie ihn danach – sonst verweist die Ausgabestelle auf eine Bezeichnung, die es nicht mehr gibt. Wie ein Textbaustein im Template eingebunden wird, steht unter [Template Engine](/frontend/die-basics/template-engine). ### Textbausteine in Konfigurationen Nicht nur Templates verweisen auf Textbausteine, sondern auch Konfigurationen. Überall dort, wo eine Konfiguration einen Text enthält, der im Frontend erscheint, kann statt eines festen Werts die Bezeichnung eines Textbausteins stehen. Das ist nicht auf System-Textbausteine beschränkt – Sie können dort auch eigene Bausteine referenzieren. Der Vorteil: Dieselbe Konfiguration lässt sich in mehreren Sprachversionen eines Shops verwenden, ohne sie je Sprache zu duplizieren. Einzelheiten unter [Verwendung von Textbausteinen in Konfigurationen](/konfiguration#verwendung-von-textbausteinen-in-konfigurationen). Ein Textbaustein, auf den eine Konfiguration verweist, lässt sich nicht löschen, solange der Verweis besteht. Entfernen Sie zuerst den Verweis in der Konfiguration. ### Nicht verwendete Bausteine aufräumen Der Filter **nicht verwendet** zeigt Textbausteine, die in keinem Template mehr vorkommen. Das ist mehr als Kosmetik. Nach einem Relaunch, einem Template-Umbau oder größeren Änderungen am Shop bleiben regelmäßig Bausteine zurück, die niemand mehr braucht. Solange sie in der Liste stehen, tauchen sie bei jeder neuen Sprache wieder auf – und werden mitübersetzt. Wer vor dem Hinzufügen eines neuen Subshops oder einer neuen Sprache einmal nach nicht verwendeten Bausteinen filtert und aufräumt, spart genau diesen Aufwand. Es werden dann nur noch die Texte angezeigt und übersetzt, die der Shop tatsächlich ausgibt. Prüfen Sie vor dem Löschen, ob der Stand aktuell ist: Die Verwendung wird bei der Template-Kompilierung ermittelt (siehe [Wirkung im Shop](#wirkung-im-shop)). Direkt nach einer Template-Änderung ohne erneutes Veröffentlichen ist die Anzeige noch nicht auf dem neuesten Stand. ## Sprachen anlegen und zuweisen Dieser Abschnitt betrifft die Shop-Administration. Für die tägliche Redaktionsarbeit wird er nicht gebraucht – er erklärt, wie die Sprachen entstehen, mit denen der Textbaustein-Dienst arbeitet. Sprachen werden nicht im Textbaustein-Dienst gepflegt, sondern in der Shop-Konfiguration. Drei Schritte gehören dazu, und ihre Reihenfolge erklärt zugleich, wie die Vererbung funktioniert. ### 1. Die Sprache anlegen Jede Sprache ist ein eigener Konfigurationsknoten unter `general.language` mit einem Namen und einem ISO-Code. Referenz und Parameter: [`general` – Allgemeine Shopeinstellungen](/konfiguration/general-allgemeine-shopeinstellungen). ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https:///admin/config/general.language ``` Sobald eine Sprache existiert, erscheint sie im Textbaustein-Dienst als wählbare Spalte – zunächst überall rot, weil noch kein Text gepflegt ist. ### 2. Die Sprache einem Subshop zuweisen Ein Subshop bekommt **genau eine** Sprache. Sie wird an zwei Stellen hinterlegt, und beide müssen dieselbe Sprache nennen: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https:///admin/config/general.subshopView https:///admin/config/general.subshop ``` Am häufigsten übersehen wird, dass es zwei Stellen sind. Wird nur eine geändert, bleibt der Fehler unauffällig, weil der Shop weiterhin Texte anzeigt – nur die falschen. Ein österreichischer Subshop erscheint dann etwa weiterhin mit deutschen Texten, obwohl österreichische Sprachvarianten gepflegt sind. Prüfen Sie in diesem Fall zuerst, ob `general.subshopView` und `general.subshop` dieselbe Sprache nennen. ### 3. Ersatzsprachen hinterlegen Textblocks Languagechains Damit nicht jede Sprachvariante vollständig gepflegt werden muss, kann eine Sprache eine geordnete Reihe von **Ersatzsprachen** besitzen. Fehlt ein Text in der eigentlichen Sprache oder ist er leer, greift die nächste Sprache dieser Reihe. Wichtig ist, wo diese Reihe hinterlegt wird: **Sie gehört zur Sprache, nicht zum Subshop.** Der Subshop bringt nur seine eine Sprache mit; welche Ersatzsprachen dahinter stehen, entscheidet die Sprache selbst. Daraus ergibt sich die wirksame Reihenfolge: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Sprache des Subshops → deren Ersatzsprache 1 → deren Ersatzsprache 2 → … ``` Ein Beispiel für einen österreichischen Subshop: 1. Der Subshop bekommt die Sprache **Deutsch (AT)**. 2. Bei der Sprache **Deutsch (AT)** wird **Deutsch** als Ersatzsprache eingetragen. 3. Ergebnis: Fehlt ein Text auf Deutsch (AT), zeigt der Shop den deutschen Text. Die Kette zeigt also immer von der **spezielleren** Sprache zur allgemeineren. Wer von WEBSALE V8s kommt, erwartet häufig das umgekehrte Muster: eine Mastersprache `DEU`, bei der die Varianten `AT` und `CH` als Ersatzsprachen hinterlegt werden. Das führt nicht zum Ziel und ist die häufigste Ursache dafür, dass ein Subshop trotz gepflegter Sprachvariante die Texte der Basissprache zeigt. Richtig ist umgekehrt: `AT` und `CH` sind eigene Sprachen, und bei **jeder** von ihnen wird `DEU` als Ersatzsprache eingetragen. Ketten können mehrstufig sein – etwa eine sehr spezielle Variante, die zunächst auf eine allgemeinere und erst danach auf die Basissprache zurückfällt. Dabei gilt: **Die Kette wird nicht weitervererbt.** Jede Sprache trägt ihre vollständige Reihe selbst. Damit `de-at-b2b` über `de-at` bis `de` durchfällt, müssen bei `de-at-b2b` beide eingetragen sein. Es genügt nicht, dass `de-at` seinerseits auf `de` verweist. Der Effekt für die Redaktion: Es ist nicht nötig, jeden Text in jeder Sprachvariante zu pflegen. Es reicht, die Basissprache vollständig zu pflegen. Speziellere Varianten übernehmen deren Inhalte automatisch, solange sie keinen eigenen Text haben. Erst wenn eine Variante einen abweichenden Text braucht, tragen Sie ihn dort gezielt ein – er überschreibt dann nur für diese Sprache die geerbte Fassung. Für die Ausgabe im Shop verhalten sich **leer** und **nicht vorhanden** gleich: Beide lösen den Rückgriff auf die Ersatzsprache aus. Ein bewusst leer gespeicherter Text unterdrückt die Ausgabe also nicht – solange eine Sprache der Kette einen Text enthält, wird dieser angezeigt. Um an einer Stelle wirklich nichts anzuzeigen, muss der Text in allen Sprachen der Kette leer oder nicht vorhanden sein. Der Unterschied zwischen den beiden Zuständen ist damit vor allem ein Merkmal für die Redaktion: Er zeigt, ob eine Sprache bereits bearbeitet wurde. ## Wirkung im Shop Zwei Punkte sind für das Verständnis zentral, weil sie leicht zu Verwirrung führen: Ein Textbaustein wird nur angezeigt, wenn er an der passenden Stelle im Template eingebunden ist. Das Anlegen oder Ändern eines Textbausteins allein reicht nicht aus. Die jeweilige Shop-Seite muss an der betreffenden Stelle auch tatsächlich auf diesen Textbaustein verweisen. Ändert man einen bereits eingebundenen Textbaustein, wirkt sich das direkt aus. Ein komplett neuer Textbaustein erscheint im Frontend erst, sobald er zusätzlich ins jeweilige Template eingefügt wurde. Bis zur Veröffentlichung befinden sich Anpassungen im Bearbeitungsstand, ohne dass Kunden sie bereits sehen. Beim Veröffentlichen werden die Templates mit den zuletzt geänderten Texten neu kompiliert – derselbe Vorgang, der auch den Verwendungs-Stand neu berechnet. Daraus folgt für den Filter **Verwendung**: Er spiegelt den Stand der letzten Kompilierung wider, nicht den aktuellen Template-Inhalt. Nach Änderungen an Templates ist er erst nach erneutem Veröffentlichen aktuell. Eine reine Textänderung ohne Template-Änderung verändert die Verwendung nicht. ## Import und Export Textblocks Export Größere Mengen an Textbausteinen lassen sich exportieren und wieder importieren, beispielsweise um sie extern übersetzen zu lassen oder um Änderungen gesammelt einzuspielen. Dies kann auf eine einzelne Sprache eingeschränkt werden, sodass beispielsweise nur die französischen Texte exportiert, extern übersetzt und anschließend wieder importiert werden. Der Export berücksichtigt die aktuell gesetzte Suche sowie die gesetzten Filter. Beide Vorgänge laufen im Hintergrund und werden durch eine Fortschrittsanzeige begleitet. Importierte Texte werden ebenfalls erst nach der Veröffentlichung im Shop sichtbar. System-Textbausteine lassen sich per Import aktualisieren, aber nicht neu anlegen – das Präfix `ws.` bleibt dem System vorbehalten. Vor größeren oder destruktiven Aktionen empfiehlt sich ein Export als Sicherung, weil sich ein Export unverändert wieder importieren lässt. ## Wegweiser * [Template Engine](/frontend/die-basics/template-engine) – wie Textbausteine im Template eingebunden werden. * [actions – Fehlertexte & E-Mails](/konfiguration/actions-fehlertexte-e-mails) – wie die System-Fehlertexte (`ws.error.*`) aufgebaut sind. * [Übersicht – Konfiguration](/konfiguration#verwendung-von-textbausteinen-in-konfigurationen) – wie Konfigurationen auf Textbausteine verweisen, statt feste Texte zu enthalten. * [`general` – Allgemeine Shopeinstellungen](/konfiguration/general-allgemeine-shopeinstellungen) – Referenz zu `general.language`, `general.subshop` und `general.subshopView`. * [Konfigurations-Deeplinks](/admin-interface/konfigurations-deeplinks) – direkte Links zu den Konfigurationsknoten. * [API-Referenz Textbausteine](/schnittstellen/admin-interface-api/api-referenz-textbausteine) – Endpunkte, Filter und Import-/Export-Schnittstelle. # accounts - Benutzerkonten Source: https://dokumentation.websale.de/konfiguration/accounts-benutzerkonten Konfiguration des accounts-Knotens: Benutzerkonten im WEBSALE Shop mit Registrierung, Login, Passwortregeln, Auto-Login sowie Adress- und Zahlungsdaten. Der Konfigurationsknoten `accounts` umfasst alle nötigen Einstellungen rund um die Verwaltung von Benutzerkonten im Onlineshop. Er definiert, wie sich Kundinnen und Kunden registrieren, anmelden, eingeloggt bleiben und welche Daten sie im Kundenkonto einsehen oder bearbeiten können. Darüber hinaus enthält er sicherheitsrelevante Parameter wie Passwortprüfungen, Login-Sperren, Auto-Login-Regeln sowie die Verwaltung von Zahlungs- und Adressdaten. Über diese Konfiguration lässt sich das Verhalten des Kundenkontos individuell an die Anforderungen des Shops anpassen – von der einfachen Anmeldung bis zur detaillierten Steuerung von Berechtigungen und Datenfeldern. *** ## `accounts*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `accounts`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accounts": { "account": {...}, "accountRestrictions": {...}, "addressFieldsSettings":{...}, "addressField":{...}, "autoLogin": {...}, "bankInfoField": {...}, "creditCardField": {...}, "customAddressField": {...}, "watchListField": {...} } } ``` #### Parameterbeschreibungen | **Parameter** | **Beschreibung** | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `account` | Steuert die zentralen Kontoeinstellungen für Kundinnen und Kunden, beispielsweise Sicherheitsprüfungen, Passwortregeln und Login-Schutzmechanismen. | | `accountRestrictions` | Begrenzt die Verfügbarkeit von Kundenkonten auf definierte Subshops. | | `addressFieldsSettings` | Steuert übergreifende Konfigurationen für Adressfelder, beispielsweise individuelle Beschriftungen, Standardwerte und Schreibschutzregeln. | | `addressField` | Definiert Struktur und Validierungsregeln für einzelne Adressfelder. | | `autoLogin` | Steuert das "Angemeldet bleiben"-Verhalten für Kundenkonten, inkl. Ablaufzeiten und Aktionsberechtigungen. | | `bankInfoField` | Ermöglicht die Erfassung und Verwaltung von Bankdaten im Kundenkonto. | | `creditCardField` | Konfiguriert die Anzeige pseudonymisierter Kreditkartendaten im Kundenkonto. | | `customAddressField` | Ermöglicht die Definition zusätzlicher individueller Adressfelder für Rechnungs- und Lieferadressen. | | `watchListField` | Definiert Felder der Merk- bzw. Beobachtungsliste mit eindeutiger ID und Namen.
    Diese Felder sind ausschließlich über die API ansprechbar und besitzen keine Konfigurationsmöglichkeit im Admin Interface. | *** ## `accounts.account` - Benutzerkonto Steuert die zentralen Kontoeinstellungen für Kundinnen und Kunden. Hier werden Sicherheitsprüfungen, Passwortregeln, Login-Schutzmechanismen und weitere Kontofunktionen festgelegt. Die Konfiguration beeinflusst das Verhalten beim Anlegen, Anmelden und Verwalten von Kundenkonten im Shop. Die Einstellungen zu diesem Abschnitt befinden sich im Admin Interface unter . #### Beispielkonfiguration für alle Subshops (`accounts.account`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountActivation": { "enabled": true, "requireOptIn": true }, "additionalPasswordCheckLevels": [ { "checks": [ { "options": { "len": 8 }, "service": "dataChecker.minLength" } ] }, { "checks": [ { "options": { "minChars": 1 }, "service": "dataChecker.digitClass" }, { "options": { "minChars": 1 }, "service": "dataChecker.specialClass" } ] } ], "confirmationOfRegistrationEmail": { "fromAddress": "", "fromName": "", "subject": "", "template": "" }, "duplicate": { "checkExistence": false, "keepAccount": true, "foundEmail": { "template": "", "subject": "", "fromAddress": "", "fromName": "" }, "informFullAddress": true, "keepSignsInInformAddress": 3 }, "errorCodes": { "passwordResetRequired": "" }, "login": { "ipBlockCount": 3, "ipBlockCountDuration": 1, "ipBlockDuration": 10, "ipBlockEnabled": true, "loginBlockCount": 5, "loginBlockDuration": 180, "loginBlockEmail": { "fromAddress": "noreply@websale.de", "fromName": "Mein Onlineshop", "subject": "Mein Onlineshop | Ihr Login wurde gesperrt", "template": "loginBlocked.htm" }, "loginCountDuration": 60 }, "newCustomerRules": [ { "field": "customerNumber", "type": "filled" } ], "passwordChecks": [ { "options": { "len": 64 }, "service": "dataChecker.maxLength" } ], "saveCreditCardData": false, "sendConfirmationOfRegistrationEmail": true, "subAccountsEnabled": false } ``` #### Parameterbeschreibungen | **Parameter** | **Typ** | **Beschreibung** | | ------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `accountActivation` | object | Konfiguration für die Bestandskundenregistrierung.
    Ermöglicht die Aktivierung eines bereits im Shop angelegten Kundendatensatzes (beispielsweise per Import) über die Aktion [AccountActivate](/frontend/referenz/aktionen/account#accountactivate).
    Das Konto gilt als noch nicht aktiviert, wenn: noch kein Passwort gesetzt ist, dem Account keine Mitarbeiterkonten zugeordnet sind oder bisher kein Einladungslink versendet wurde.
    Aus Sicherheitsgründen kann die Aktivierung nur einmal durchgeführt werden. Welche Felder bei der Bestandskundenregistrierung abgefragt werden, wird [hierüber](/konfiguration/customer-kundendaten#customer-customerdatafieldsettings-feldkonfiguration) gesteuert. | | `enabled` | bool | Aktiviert (`true`) bzw. deaktiviert (`false`) die Bestandskundenregistrierung. | | `requireOptIn` | bool | Steuert, ob nach der Aktivierung eine Opt-In E-Mail an die hinterlegte Adresse versendet wird, die die Registrierung bestätigen muss.
    Default: `true` | | `additionalPasswordCheckLevels` | list | Zusätzliche Prüfungen für Passwörter.
    Ermöglicht gestaffelte Sicherheitsanforderungen, etwa Mindestlänge oder bestimmte Zeichengruppen (Zahlen, Sonderzeichen). | | `checks` | multiService | Liste von Prüfregeln innerhalb eines Levels; alle enthaltenen Checks müssen erfüllt sein. | | `service` | string | Prüftyp (beispielsweise `dataChecker.minLength`, `dataChecker.maxLength`, `dataChecker.digitClass`, `dataChecker.specialClass`). | | `options` | array | Optionsobjekt für den jeweiligen Prüftyp.
    [Hier gibt es mehr Informationen zu den Validierungs- und Prüfservices](/konfiguration/validierungs-und-prufservices). | | `confirmationOfRegistrationEmail` | object | Konfiguration der Registrierungsbestätigungs-E-Mail.
    Wird nur genutzt, wenn `sendConfirmationOfRegistrationEmail` = `true` ist.
    Die E-Mail kann beispielsweise eine Möglichkeit zur Stornierung der Anfrage über einen Link enthalten. | | `fromAddress` | string | Absenderadresse, die im E-Mail-Versand verwendet wird. | | `fromName` | string | Anzeigename des Absenders in der E-Mail. | | `subject` | string | Betreffzeile der Registrierungsbestätigungs-E-Mail. | | `template` | string | Name oder Pfad der zu verwendenden [E-Mail-Vorlage](/konfiguration/messages-ereignisgesteuerte-e-mails). | | `duplicate` | object | Sammelobjekt für alle Einstellungen der Duplettenprüfung bei der Registrierung. | | `checkExistence` | bool | Aktiviert (`true`) bzw. deaktiviert (`false`) die Duplettenprüfung.
    Default: `false` | | `keepAccount` | bool | Legt fest, ob das Konto auch dann angelegt wird, wenn die Prüfung eine Dublette findet (`true` = trotzdem anlegen). | | `foundEmail` | object | Mailkonfiguration für den Versand an die gefundene(n) Dublette(n). Im Mailtemplate kann über `$wsRequestVariables.email` die bei der Registrierung angegebene E-Mail-Adresse ausgegeben werden – beispielsweise damit der Account-Admin ein Subaccount für den Nutzer anlegen kann. | | `template` | string | Name oder Pfad der E-Mail-Vorlage. | | `subject` | string | Betreffzeile der E-Mail. | | `fromAddress` | string | Absenderadresse der E-Mail. | | `fromName` | string | Anzeigename des Absenders. | | `informFullAddress` | bool | Steuert, ob in den Fehlerdetails der Meldung `duplicateAccountFound` (Aktion `accountRegister`) die gefundene Dubletten-Mailadresse unzensiert (`true`) oder zensiert (`false`) ausgegeben wird. | | `keepSignsInInformAddress` | int | Nur wirksam, wenn `informFullAddress` = `false`: Anzahl der Zeichen im Local-Part der Mailadresse (alles vor dem `@`), die beibehalten werden. Alle übrigen Zeichen werden durch `*` ersetzt. | | `passwordChecks` | array | Basis-Passwortprüfungen (werden immer angewendet). Aufbau identisch zu `additionalPasswordCheckLevels`. | | `service` | string | Prüftyp (beispielsweise `addressCheck.minLength`, `dataChecker.minLength` für Prüfung einer Mindestangabe, `addressCheck.maxLength`, `dataChecker.maxLength` für Prüfung maximaler Zeichenangabe etc.).
    Übersicht der verfügbaren Validierungs- und Prüfregeln für Adressdatenfelder finden Sie [hier](/konfiguration/validierungs-und-prufservices). | | `options` | array | Optionsobjekt für den jeweiligen Prüftyp. | | `errorCodes` | object | Sammelobjekt für besondere Fehlerzustände. | | `passwordResetRequired` | string | Schlüssel/Code, der ausgegeben wird, wenn für das Benutzerkonto eine Passwortzurücksetzung erforderlich ist (beispielsweise nach einem administrativen Reset oder aus Sicherheitsgründen).
    Wird vom System vorgegeben und kann nicht verändert werden.

    | | `login` | object | Einstellungen für Anmelde-Schutzmechanismen. | | `ipBlockEnabled` | bool | Aktiviert (`true`) / deaktiviert (`false`) die IP-basierte Sperre. | | `ipBlockCount` | int | Anzahl fehlgeschlagener Versuche pro IP, bevor die IP gesperrt wird.
    Default: **10** | | `ipBlockCountDuration` | int | Zeitfenster in **Minuten**, in dem IP-Versuche gezählt werden.
    Default: **1** | | `ipBlockDuration` | int | Sperrdauer der IP in **Minuten**. | | `loginBlockCount` | int | Anzahl fehlgeschlagener Logins pro Konto, bevor das Konto gesperrt wird.
    Default: **5** | | `loginCountDuration` | int | Zeitfenster in **Minuten**, in dem Konto-Versuche gezählt werden.
    Default: **60** | | `loginBlockDuration` | int | Kontosperrdauer in **Minuten**.
    Default: **180** | | `loginBlockEmail` | object | E-Mail-Benachrichtigung bei Kontosperre. | | `fromAddress` | string | Absenderadresse (E-Mail). | | `fromName` | string | Anzeigename des Absenders. | | `subject` | string | Betreff der E-Mail. | | `template` | string | Vorlagenname/Datei (beispielsweise `loginBlocked.htm`). | | `newCustomerRules` | array | Regeln, nach denen ein eingeloggter Kunde im Bestellablauf als Neukunde (`newCustomer`) eingestuft wird - beispielsweise um Zahlungsarten für Neukunden zu sperren. Details siehe [Neukunden-Regeln](#neukunden-regeln-newcustomerrules). Bei `null` oder leerer Liste gilt kein eingeloggter Kunde als Neukunde. | | `saveCreditCardData` | bool | Speicherung von Kreditkartendaten im Konto erlauben (`true`/`false`). | | `sendConfirmationOfRegistrationEmail` | bool | Gibt an, ob nach der Registrierung automatisch eine Bestätigungs-E-Mail versendet wird. | | `subAccountsEnabled` | bool | Aktiviert oder deaktiviert (`true`/`false`) die Mitarbeiterkontenfunktion.
    Ist die Funktion aktiv, können für jedes übergeordnete Konto individuelle Mitarbeiterkonten angelegt werden.
    Sobald diese Funktion aktiviert ist, ist eine direkte Anmeldung am übergeordneten Konto nicht mehr möglich.
    Daher sollte die Aktivierung ausschließlich in einem neu eingerichteten Shop erfolgen – eine nachträgliche Aktivierung führt dazu, dass sich bestehende Nutzer nicht mehr anmelden können. | ### Neukunden-Regeln (`newCustomerRules`) Über `newCustomerRules` wird festgelegt, wann ein **eingeloggter Kunde** im Bestellablauf als Neukunde gilt. Der so ermittelte Kundentyp `newCustomer` wird von der Zahlungsarten-Validierung [`paymentValidation.accountType`](/konfiguration/validierungs-und-prufservices#paymentvalidation-accounttype-validierung-des-kundentyps-fur-zahlungsarten) ausgewertet - beispielsweise um Kauf auf Rechnung für Neukunden zu sperren. Jede Regel besteht aus einem Feld und einer Bedingung. Trifft die Bedingung einer Regel zu, gilt der Kunde **nicht** als Neukunde. Nur wenn keine der Regeln zutrifft, wird der Kunde als Neukunde eingestuft. #### Beispielkonfiguration (`accounts.account.newCustomerRules`) Ein Kunde gilt als Neukunde, solange ihm noch keine Kundennummer zugewiesen wurde: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "newCustomerRules": [ { "field": "customerNumber", "type": "filled" } ] } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `field` | string | Das Feld, das für die Prüfung herangezogen wird.
    Sonderfall `"customerNumber"`: die Kundennummer des Benutzerkontos.
    Alle anderen Werte werden als `dataId` eines Feldes der **Rechnungsadresse** interpretiert (Standard- oder [zusätzliche Adressfelder](#accounts-customaddressfield-weitere-adressdatenfelder)).
    Der Wert wird nicht gegen vorhandene Felder validiert - ein nicht existierendes Feld liefert immer einen leeren Wert. | | `type` | enum | Bedingung, bei deren Zutreffen der Kunde **nicht** als Neukunde gilt.
    Mögliche Werte:
    - `"filled"` - Ist das Feld gefüllt, gilt der Kunde nicht als Neukunde.
    - `"empty"` - Ist das Feld leer, gilt der Kunde nicht als Neukunde.
    Default: `"filled"` | Der Kundentyp wird beim **Login im Bestellablauf** anhand dieser Regeln ermittelt (`newCustomer` oder `customer`). Eine **Neuregistrierung** im Bestellablauf führt unabhängig von den Regeln immer zum Kundentyp `newCustomer`. Gastbesteller haben den Kundentyp `guest`. *** ## `accounts.accountRestrictions` - Subshopbeschränkungen für Benutzerkonten Begrenzt die Verfügbarkeit von Kundenkonten auf definierte Subshops, beispielsweise B2B-Konten nur für einen Länder-Shop freigeben, exklusive Bereiche je Mandant oder Region. Die Einstellungen zu diesem Abschnitt befinden sich im Admin Interface unter . #### Beispielkonfiguration für alle Subshops (`accounts.accountRestrictions`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "subshopRestrictionList": [], "subshopRestrictionsEnabled": false, "subshopRestrictionsFallback": "onlySelf" } ``` #### Parameterbeschreibungen | **Parameter** | **Typ** | **Beschreibung** | | ----------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `subshopRestrictionsEnabled` | bool | Aktiviert (`true`) oder deaktiviert (`false`) die Subshop-Beschränkungen für Kundenkonten. | | `subshopRestrictionsFallback` | enum | Fallback-Verhalten, wenn keine explizite Zuordnung greift (beispielsweise leere Liste oder fehlende Kennung). Standard: `onlySelf` – Konto ist nur im „eigenen/aktuell adressierten" Subshop nutzbar. | | `subshopRestrictionList` | list | Liste der zulässigen Subshops (Allowlist) für das Konto. Einträge müssen den in Ihrer Umgebung verwendeten Subshop-Kennungen entsprechen (beispielsweise den Schlüsseln in der Subshop-Konfiguration). Ist die Liste leer, greift das Verhalten gemäß `subshopRestrictionsFallback`. | *** ## `accounts.addressFieldsSettings` - Individuelle Adressfelder-Einstellungen Steuert die zentralen Konfigurationen für Adressfelder im Shop. Hier werden individuelle Beschriftungen, Standardwerte, Sichtbarkeiten und Schreibschutzregeln für Rechnungs- und Lieferadressen festgelegt. Die Einstellungen zu diesem Abschnitt befinden sich im Admin Interface unter . #### Beispielkonfiguration für alle Subshops (`accounts.addressFieldsSettings`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "customLabelsDefinition": [], "defaultValuesDefinition": [], "inputVisibilityDefinition": null, "readOnlyFields": null } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------------- | ------- | ----------------------------------------------------------------------------- | | `customLabelsDefinition` | list | Definition bedingungsabhängiger Feldbeschriftungen für Adressfelder. | | `defaultValuesDefinition` | list | Definiert bedingungsabhängige Standardwerte / Vorbelegungen für Adressfelder. | | `inputVisibilityDefinition` | list | Definiert die Sichtbarkeit einzelner Adressfelder. | | `readOnlyFields` | list | Definiert, welche Adressfelder nur sichtbar und nicht bearbeitbar sind. | **Bedingungsabhängige Definitionen (**`customLabelsDefinition` **&** `defaultValuesDefinition`**)** Die Definitionen `defaultValuesDefinition` und `customLabelsDefinition` ermöglichen es, Standardwerte und benutzerdefinierte Feldbezeichnungen für Adressfelder abhängig von bestimmten Bedingungen zu definieren. Beide Definitionen folgen derselben Struktur und unterstützen ein `conditions`-Array, mit dem die Anwendung der jeweiligen Regel an Feldbedingungen geknüpft werden kann. **Aufbau eines Eintrags** | **Eigenschaft** | **Typ** | **Beschreibung** | | ----------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `fields` | list | Liste der betroffenen Adressfelder (beispielsweise `accounts.addressField.firstName`). | | `addressType` | string | Adresstyp, für den die Regel gilt. `"bill"` = Rechnungsadresse, `"delivery"` = Lieferadresse. | | `label` / `value` | string | Hier wird zwischen beiden Definitionen unterschieden. `customLabelsDefinition` (`label`): die anzuzeigende Beschriftung. `defaultValuesDefinition` (`value`): der vorzubelegende Standardwert. | | `conditions` | list | Liste von Bedingungen, die alle erfüllt sein müssen, damit die Regel greift. | **Aufbau einer Condition** | **Eigenschaft** | **Typ** | **Beschreibung** | | --------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `field` | string | Das Adressfeld, auf das sich die Bedingung bezieht (beispielsweise `accounts.addressField.country`). | | `type` | string | Art der Prüfung. `value`: exakter Vergleichswert oder `filled`: Feld ist befüllt. | | `value` | string | Abhängig davon, was bei `type` definiert wurde. Bei `"value"`: der erwartete Wert (beispielsweise `"DE"`). Bei `"filled"`: ein leerer String (`""`). | **Beispiel für** `customLabelsDefinition` Benutzerdefinierte Feldbeschriftungen, die abhängig von Bedingungen angezeigt werden: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "customLabelsDefinition": [ { "fields": ["accounts.addressField.firstName"], "addressType": "bill", "label": "Vorname (Rechnung)", "conditions": [ { "field": "accounts.addressField.country", "type": "value", "value": "DE" } ] }, { "fields": ["accounts.addressField.firma"], "addressType": "delivery", "label": "Firma (Lieferung)", "conditions": [ { "field": "accounts.addressField.country", "type": "filled", "value": "" } ] } ] } ``` **Erklärung** Im ersten Eintrag wird das Feld `accounts.addressField.firstName` in der Rechnungsadresse mit dem Label „Vorname (Rechnung)" beschriftet – jedoch nur, wenn das Land auf `DE` gesetzt ist. Im zweiten Eintrag erhält das Feld `accounts.addressField.firma` in der Lieferadresse das Label „Firma (Lieferung)", sobald das Feld `accounts.addressField.country` einen beliebigen Wert enthält (`type: "filled"`). **Beispiel für** `defaultValuesDefinition` Standardwerte für Adressfelder, die ebenfalls bedingungsabhängig vorbefüllt werden: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "defaultValuesDefinition": [ { "fields": ["accounts.addressField.country"], "addressType": "bill", "value": "DE", "conditions": [] }, { "fields": ["accounts.addressField.salutation"], "addressType": "delivery", "value": "Herr", "conditions": [ { "field": "accounts.addressField.country", "type": "value", "value": "DE" } ] } ] } ``` **Erklärung** Im ersten Eintrag wird das Feld `accounts.addressField.country` in der Rechnungsadresse bedingungslos mit `"DE"` vorbelegt. Im zweiten Eintrag wird die Anrede der Lieferadresse (`accounts.addressField.salutation`) nur dann auf `"Herr"` gesetzt, wenn das Land `DE` ist. *** ## `accounts.addressField` - Einzelne Adressfelder definieren Steuert die Struktur und Eigenschaften einzelner Adressfelder im Shop. Über Validierungen können Eingaben überprüft und formale Anforderungen (beispielsweise Pflichtfelder, Formatprüfungen) festgelegt werden. Die Einstellungen zu diesem Abschnitt befinden sich im Admin Interface unter . #### Beispielkonfiguration für alle Subshops (`accounts.addressField.firstName`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "name": "firstName", "validations": [ { "options": { "len": 255 }, "service": "addressCheck.maxLength" } ] } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `label` | string | Definition der Feldbeschriftung.

    | | `name` | string | Anzeigename (in diesem Beispiel des Kunden, in anderen Fällen beispielsweise der Name der Stadt, in der der Kunde wohnt). | | `validations` | array | Definiert die Liste der Validierungsregeln, die auf das jeweilige Adressfeld angewendet werden. | | `options` | array | Definiert die Parameter oder Einstellungen, die eine Validierungsregel benötigt – beispielsweise Grenzwerte, erlaubte Zeichen oder Bedingungen. | | `len` | int | Gibt im Beispiel die maximal zulässige Zeichenlänge für die Validierung an. | | `service` | string | Bezeichnet den verwendeten Validierungsdienst, der die eigentliche Prüfung durchführt – hier beispielsweise `addressCheck.maxLength` zur Kontrolle der maximalen Feldlänge. | *** ## `accounts.autoLogin` - Angemeldet bleiben Steuert das „Angemeldet bleiben"-Verhalten (Auto-Login) für Kundenkonten: Aktivierung, Ablaufzeiten und Reaktionen auf Sonderfälle. Die Einstellungen zu diesem Abschnitt befinden sich im Admin Interface unter . #### Beispielkonfiguration für alle Subshops (`accounts.autoLogin`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "actions": null, "active": true, "errorCodes": { "actionRequiresLogin": "" }, "expireTimesInDays": { "cookie": 30, "noAutoLogin": 10, "noPasswordLogin": 20 }, "restriction": "notAllowed" } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | --------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `active` | bool | Aktiviert (`true`) oder deaktiviert (`false`) die Auto-Login-Funktion insgesamt. | | `restriction` | enum | Richtlinie für Auto-Login. Wert `notAllowed`: Auto-Login ist untersagt (keine dauerhafte Sitzung). Weitere Werte sind systemspezifisch vorbelegt. | | `expireTimesInDays` | object | Sammelobjekt mit Ablaufzeiten (in **Tagen**) für unterschiedliche Szenarien. | | `cookie` | uint | Gültigkeitsdauer des Auto-Login-Cookies in Tagen. Nach Ablauf ist ein regulärer Login erforderlich. Default: **30** | | `noAutoLogin` | uint | Maximale Inaktivitätsdauer in Tagen ohne Auto-Login; nach Ablauf wird keine automatische Anmeldung mehr versucht. Default: **10** | | `noPasswordLogin` | uint | Zeitraum in Tagen, nach dem trotz bestehendem Auto-Login eine Passwort-Eingabe erzwungen wird (beispielsweise als Re-Auth). Default: **20** | | `errorCodes` | object | Objekt für spezielle Fehlerzustände. | | `actionRequiresLogin` | string | Schlüssel/Code für den Fall, dass eine Aktion eine erneute Anmeldung erfordert. | | `actions` | list | Liste der Aktionen, die während eines automatischen Logins **ohne erneute Passwortabfrage** erlaubt sind. Damit lässt sich gezielt festlegen, was Kunden im angemeldeten Zustand nutzen dürfen, ohne sich erneut anzumelden.
    Beispielsweise kann so der Zugriff auf unkritische Funktionen wie die Merkliste erlaubt werden, während sicherheitsrelevante Aktionen (beispielsweise Warenkorb- oder Bestellvorgänge) weiterhin eine erneute Anmeldung erfordern.
    Beispiele für erlaubte Aktionen: `WatchListAdd` → neue Merkliste anlegen, `WatchListDelete` → Merkliste löschen, `WatchListItemAdd` → Produkte auf eine Merkliste legen, `WatchListItemDelete` → Produkte von einer Merkliste löschen.
    Wenn keine Aktionen erlaubt werden sollen, muss der Wert auf `null` gesetzt werden. In diesem Fall sind alle Aktionen automatisch gesperrt, und für jede Interaktion ist eine erneute Anmeldung erforderlich. | *** ## `accounts.bankInfoField` - Bankdaten Ermöglicht die Erfassung und Verwaltung von Bankdaten im Kundenkonto. Im Gegensatz zu Kreditkartendaten können diese Informationen direkt im Shop eingegeben, geändert und gespeichert werden. Die gespeicherten Bankverbindungen stehen anschließend im Bestellprozess – insbesondere bei der Zahlart SEPA-Lastschrift – zur Auswahl. #### Beispielkonfiguration für alle Subshops (`accounts.bankInfoField.owner`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "dataId": "owner", "label": "Kontoinhaber", "name": "owner" } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `dataId` | string | Interne Kennung des Datenfeldes (beispielsweise „owner"). | | `label` | string | Anzeigename im Kundenkonto, beispielsweise „Kontoinhaber". | | `name` | string | Technischer Feldname. Wird vom System vorgegeben und sollte nicht verändert werden. Folgende `name` stehen zur Verfügung:
    - `accountNumber` - Kontonummer der Kundin bzw. des Kunden (in der Regel nur bei älteren Konten ohne IBAN relevant)
    - `bankCode` - Bankleitzahl (nur relevant, wenn keine IBAN verwendet wird)
    - `bankName` - Name der Bank
    - `bic` - BIC (Business Identifier Code) der Bank
    - `iban` - IBAN (International Bank Account Number) der Kontoinhaberin bzw. des Kontoinhabers
    - `owner` - Name der Kontoinhaberin bzw. des Kontoinhabers
    - `sepaDebitType` - Art der SEPA-Lastschrift (beispielsweise CORE oder B2B)
    - `sepaDirectDebitMandate` - Mandatsreferenznummer der SEPA-Lastschrift
    - `sepaMandateDate` - Datum der Mandatserteilung (ISO-Format empfohlen: YYYY-MM-DD)
    - `sepaMandateType` - Typ des SEPA-Mandats (beispielsweise Erstmandat oder Folgemandat) | *** ## `accounts.creditCardField` - Kreditkarten Die Bezahlung mit Kreditkarte wird aus Sicherheitsgründen ausschließlich über externe Payment-Service-Provider (PSP) abgewickelt. Die Eingabe der Kreditkartendaten, die Erkennung des Kartentyps sowie die Durchführung des 3D Secure 2.0-Verfahrens erfolgen vollständig beim Payment-Provider. Reale Kreditkartendaten werden niemals im Onlineshop gespeichert oder verarbeitet. Im Kundenkonto können – sofern vom PSP unterstützt und vertraglich freigeschaltet – pseudonymisierte Kreditkarteninformationen angezeigt werden. Dadurch können Kunden beim nächsten Einkauf bequem eine gespeicherte Karte auswählen, ohne die Daten erneut eingeben zu müssen. Eine direkte Eingabe oder Änderung von Kreditkartendaten im Shop ist dabei nicht möglich. #### Beispielkonfiguration für alle Subshops (`accounts.creditCardField.holder`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "dataId": "holder", "label": "Kreditkarten-Inhaber", "name": "holder" } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `dataId` | string | Interne Kennung des Datenfeldes (beispielsweise „holder"). | | `label` | string | Anzeigename im Kundenkonto, beispielsweise „Kreditkarten-Inhaber". | | `name` | string | Technischer Feldname. Wird vom System vorgegeben und sollte nicht verändert werden. Folgende `name` stehen zur Verfügung:
    - `cvCode` - Sicherheitscode (3 oder 4 Stellen, je nach Kartentyp)
    - `expireMonth` - Ablaufmonat der Karte
    - `expireYear` - Ablaufjahr der Karte
    - `holder` - Karteninhaberin bzw. Karteninhaber
    - `number` - Kartennummer (pseudonymisiert)
    - `type` - Kartentyp (beispielsweise Visa, MasterCard, American Express) | *** ## `accounts.customAddressField` - Weitere Adressdatenfelder Ermöglicht die Definition zusätzlicher Adressfelder für Rechnungs- und/oder Lieferadressen. Diese Felder ergänzen die Standardangaben (beispielsweise Name, Straße, PLZ, Ort, Land, Telefon) um individuelle Eingabefelder, die im Kundenkonto oder im Checkout angezeigt und gespeichert werden. Beispiele für typische Zusatzfelder sind: *Adresszusatz*, *Etage*, *Postfach*, *Packstationnummer* oder *Abteilung*. #### Beispielkonfiguration für alle Subshops (`accounts.customAddressField.postOfficeBox`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "dataId": "customField.postfach", "label": "", "name": "postfach", "validations": [ { "options": { "len": 3 }, "service": "addressCheck.minLength" }, { "options": { "len": 20 }, "service": "addressCheck.maxLength" }, { "options": { "signs": "^[0-9A-Za-z\\s-]+$" }, "service": "addressCheck.legalSigns" } ] } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `dataId` | string | Interne Kennung oder Referenz-ID des Feldes (beispielsweise zur Verknüpfung mit externen Systemen oder Datenquellen). | | `label` | string | Anzeigename des Feldes im Frontend (beispielsweise „Etage" oder „Packstationnummer").

    | | `name` | string | Technischer Feldname, der intern für Speicherung und Zuordnung verwendet wird. | | `validations` | array | Optionales Validierungsobjekt zur Prüfung der Eingabe (beispielsweise Pflichtfeld, maximale Länge, bestimmte Zeichenformate). Kann `null` sein, wenn keine Validierung erforderlich ist. Übersicht der verfügbaren Validierungs- und Prüfregeln für Adressdatenfelder finden Sie [hier](/konfiguration/validierungs-und-prufservices). | *** ## `accounts.watchListField` - Merkliste Definiert Felder der Merk- bzw. Beobachtungsliste mit eindeutiger ID und Namen. Diese Felder sind ausschließlich über die API ansprechbar und besitzen keine Konfigurationsmöglichkeit im Admin Interface. #### Beispielkonfiguration für alle Subshops (`accounts.watchListField`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "watchListIds" } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | Technischer Name des Watchlist-Feldes. Dient zur eindeutigen Identifizierung des Feldes innerhalb der API und interner Prozesse. | # app - WEBSALE APP Source: https://dokumentation.websale.de/konfiguration/app-websale-app Konfiguration des app-Knotens für die WEBSALE APP: Aktivierungsstatus, Authentifizierung, Push-Benachrichtigungen sowie zugehörige Service-Accounts. Der Knoten `app` umfasst alle Konfigurationen für die Anbindung und Steuerung der WEBSALE APP.\ Über diesen Abschnitt werden zentrale App-Parameter wie Aktivierungsstatus, Authentifizierung, Benachrichtigungseinstellungen sowie zugehörige Service-Accounts definiert. Die Konfiguration kann direkt im Admin Interface unter *Einstellungen → Shop-Konfiguration → Gruppe „App"* oder über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) vorgenommen werden. *** ## `app*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `app` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "app": {...}, "googleServiceAccount": {...}, "instances": {...} } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ---------------------- | ----------------------------------------------------------------------------------------------------------- | | `app` | Steuert Anbindung und Verhalten der WEBSALE APP (Aktivierung, Token-Prüfung, Verbindungsdaten, Grenzwerte). | | `googleServiceAccount` | Definiert die Verbindung zu einem Google-Service-Account, z. B. für den Versand von Push-Nachrichten. | | `instances` | Definiert einzelne App-Instanzen (z. B. pro Land, Marke oder Kanal). | *** ## `app.app` - Konfiguration der WEBSALE APP Der Knoten `app` steuert die Anbindung und das Verhalten der WEBSALE App. Hier wird unter anderem festgelegt, ob die App-Integration aktiv ist, wie Tokens geprüft werden, welche Shop-Verbindungsdaten verwendet werden und welche Daten- und Filtergrenzen gelten. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": false, "applicationId": "", "enableTokenValidation": true, "filterLimits": { "maxEmailListSize": 500000, "maxZipCodeListSize": 50000, "maxZipCodeRangeSize": 5000 }, "googleServiceAccount": null, "imageFormats": null, "notificationSettings": { "defaultSettings": { "basketReminder": "undefined", "birthdayGreetings": "undefined", "deliveryNotification": "undefined", "news": "undefined", "teaser": "undefined" }, "personalizedMessages": { "basketReminder": false, "birthdayGreetings": false, "deliveryNotification": false }, "pushNotificationBatchSize": 500 }, "secret": "", "v8": null } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `active` | bool | Aktiviert (`true`) oder deaktiviert (`false`) die WEBSALE APP.
    Default: `false` | | `applicationId` | string | Eindeutige Kennung der App (Application ID). | | `enableTokenValidation` | bool | Aktiviert (`true`) oder deaktiviert (`false`) die Tokenprüfung für App-Zugriffe.
    Default: `true` | | `filterLimits` | object | Grenzwerte für App-interne Filterfunktionen. | | `maxEmailListSize` | uint | Maximale Anzahl an E-Mail-Adressen in einer Filterliste.
    Default: `500000` | | `maxZipCodeListSize` | uint | Maximale Anzahl an Postleitzahlen in einer Filterliste.
    Default: `500000` | | `maxZipCodeRangeSize` | uint | Maximale Anzahl an Postleitzahlenbereichen.
    Default: `5000` | | `googleServiceAccount` | assoc | Verweis auf das konfigurierte Google-Servicekonto (siehe Abschnitt `app.googleServiceAccount`). | | `oAuthKey` | -- | `authentication.googleOAuthKey.FCMKey` | | `scopes` | -- | [https://www.googleapis.com/auth/firebase.messaging](https://www.googleapis.com/auth/firebase.messaging) | | `imageFormats` | list | Definiert die im App-Frontend verwendeten Bildformate (Mehrfachzuordnung über `content.imageFormat`).
    → [content - Katalog (Kategorien & Produkte)](/konfiguration/content-katalog-kategorien-produkte) | | `notificationSettings` | object | Einstellungen für Standard- und personalisierte Push-Benachrichtigungen. | | `defaultSettings` | object | Standardwerte für Benachrichtigungstypen (z. B. Warenkorberinnerung, Lieferstatus) beim Start der App. | | `basketReminder` | enum | Aktiviert (`true`) oder deaktiviert (`false`) die Benachrichtigung bei stehengelassenen Warenkörben. | | `birthdayGreetings` | enum | Aktiviert (`true`) oder deaktiviert (`false`) die Geburtstags-Benachrichtigung.
    Um Geburtstagsbenachrichtigungen zu versenden, muss der Empfänger ein Geburtsdatum angegeben haben | | `deliveryNotification` | enum | Standardvorgabe für Versand-/-Lieferbenachrichtigungen. | | `news` | enum | Standardvorgabe für Newsletter-Benachrichtigungen. Werte: `undefined`, `enabled`, `disabled` | | `teaser` | enum | Standardvorgabe für Marketing-Nachrichten. | | `personalizedMessages` | object | Aktiviert/deaktiviert personalisierte Nachrichten-Typen. | | `basketReminder` | enum | Standardvorgabe für die Erinnerung an liegengelassene Warenkörbe. | | `birthdayGreetings` | enum | Standardvorgabe für Geburtstagsgrüße. | | `deliveryNotification` | enum | Standardvorgabe für Versand-/-Lieferbenachrichtigungen. | | `pushNotificationBatchSize` | uint | Anzahl an Push-Nachrichten, die in einem Batch verarbeitet/versendet werden.
    Beispiel: `500` | | `secret` | string | Geheimer Schlüssel zur Validierung von Tokens für die App-Kommunikation. | | `v8` | object | Optionale Detailkonfiguration für die Kopplung an den V8-Shop. | | `osbAuth` | object | Zugangsdaten für die OSB-/Backend-Kommunikation der App. | | `username` | string | Technischer Benutzername für die OSB-/Backend-Anbindung. | | `password` | string | Passwort für diesen technischen Benutzer. | | `shopId` | string | Kennung des angebundenen Shops im Backend. | | `shopUrl` | string | Basis-URL des Shops, der von der App verwendet wird. | | `shopPassword` | string | Passwort für die Shop-Anbindung. | | `personalizedDataFetchLimit` | uint | Max. Anzahl personalisierter Datensätze, die pro Abruf geladen werden dürfen.
    Default: `500` | | `voucherCodesFetchLimit` | uint | Max. Anzahl Gutscheincodes, die pro Abruf geladen werden dürfen.
    Default: `200` | *** ## `app.googleServiceAccount` - Push-Nachrichten Der Knoten `googleServiceAccount` definiert die Verbindung zu einem Google-Service-Account, beispielsweise für den Versand von Push-Nachrichten. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "oAuthKey": "authentication.googleOAuthKey.FCMKey", "scopes": [ "https://www.googleapis.com/auth/firebase.messaging" ] } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `oAuthKey` | singleAssoc | Verweist auf einen hinterlegten Google OAuth-Schlüssel, der die Zugangsdaten (Key/JSON) des Service Accounts enthält.
    Target: `authentication.googleOAuthKey` | | `scopes` | list (string) | Liste der OAuth-Scopes, die für den Service Account angefordert werden. | *** ## `app.instances` - APP-Instanzen Der Knoten `instances` definiert einzelne App-Instanzen der WEBSALE App, typischer pro Land, Marke oder Kanal. Für jede Instanz können unter anderem Basis-URLs, Länderinformationen und abweichende Benachrichtigungseinstellungen konfiguriert werden. #### Beispielkonfiguration `app.instances.deutsch` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "base_url": "", "country": "", "country_code": "", "id": "", "label": "", "notificationSettings": { "defaultSettings": { "basketReminder": "undefined", "birthdayGreetings": "undefined", "deliveryNotification": "undefined", "news": "undefined", "teaser": "undefined" }, "personalizedMessages": { "basketReminder": false, "birthdayGreetings": false, "deliveryNotification": false } }, "shop_url": "", "v8": { "base_url": "" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------------- | ------- | --------------------------------------------------------------------------------------------------- | | `base_url` | string | Basis-URL der App-Instanz. | | `country` | string | Name des Landes, dem die Instanz zugeordnet ist. | | `country_code` | string | Ländercode der Instanz (z.B. `DE`, `AT`). | | `id` | string | Eindeutige Kennung der App-Instanz (z.B. `de_shop`, `eu_shop`). | | `label` | string | Lesbarer Name der Instanz (z.B. “Deutschland-Shop”, “EU-App”). | | `notificationSettings` | object | Optionale Benachrichtigungseinstellungen, die die globalen App-Defaults überschreiben können. | | `defaultSettings` | object | Definiert die Standard-Voreinstellungen für Benachrichtigungen in dieser Instanz. | | `basketReminder` | bool | Aktiviert/Deaktiviert personalisierte Warenkorberinnerungen. | | `birthdayGreetings` | bool | Aktiviert/Deaktiviert personalisierte Geburtstagsgrüße. | | `deliveryNotification` | bool | Aktiviert/Deaktiviert personalisierte Liefer-/Versandbenachrichtigungen. | | `news` | enum | Standardvorgabe für Newsletter-Benachrichtigungen.
    Werte: `undefined`, `enabled`, `disabled` | | `teaser` | enum | Standardvorgabe für Werbehinweise. | | `personalizedMessages` | object | Aktiviert/Deaktiviert bestimmte personalisierte Nachrichten für diese Instanz. | | `basketReminder` | bool | Aktiviert/Deaktiviert personalisierte Warenkorberinnerungen. | | `birthdayGreetings` | bool | Aktiviert/Deaktiviert personalisierte Geburtstagsgrüße. | | `deliveryNotification` | bool | Aktiviert/Deaktiviert personalisierte Liefer-/Versandbenachrichtigungen. | | `shop_url` | string | URL des zugehörigen Onlineshops, die in der App verwendet wird. | | `v8` | object | Optionale V8-spezifische Konfiguration für diese Instanz. | | `base_url` | string | Basis-URL der angebundenen V8-Shop-Instanz für diese App-Instanz. | *** # authentication - Authentifizierungs- & Zugriffsdaten Source: https://dokumentation.websale.de/konfiguration/authentication-authentifizierungs-zugriffsdaten Der authentication-Knoten verwaltet Zugangsdaten externer Authentifizierungsprovider wie Google OAuth 2.0 und Firebase Cloud Messaging im WEBSALE Shop. Der Konfigurationsbereich `authentication` dient der Verwaltung von Authentifizierungsinformationen und Zugangsdaten für externe Dienste, Schnittstellen oder Systeme. Über diesen Bereich können zukünftig verschiedene Authentifizierungsprovider (z. B. Google, Apple, Microsoft oder eigene OAuth-Dienste) eingebunden werden. Jede Authentifizierungseinheit wird dabei als eigener Eintrag mit individuellen Parametern konfiguriert. Aktuell steht die Konfiguration für Google OAuth 2.0 zur Verfügung, die über den Eintrag\ `authentication.googleOAuthKey.FCMKey` die Zugangsdaten eines Google-Service-Accounts für Firebase Cloud Messaging (FCM) verwaltet. *** ## `authentication*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `authentication` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "authentication": { "googleOAuthKey": {...} } } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ---------------- | ---------------------------------------------- | | `googleOAuthKey` | Authentifizierung für Firebase Cloud Messaging | *** ## `authentication.googleOAuthKey.FCMKey` - Authentifizierung für Firebase Cloud Messaging Damit das Shopsystem Push-Nachrichten z. B. über die App oder den Browser senden kann, benötigt es eine Authentifizierung gegenüber Firebase. Der Konfigurationsabschnitt `authentication.googleOAuthKey.FCMKey` enthält die Zugangsdaten für den Google-Service-Account, der für die Authentifizierung gegenüber Firebase Cloud Messaging (FCM) verwendet wird. Diese Daten ermöglichen es dem System, Push-Benachrichtigungen über die Google-Infrastruktur zu senden oder andere FCM-bezogene Aktionen automatisiert durchzuführen. Jeder Eintrag stellt die vollständigen Authentifizierungsinformationen des Service-Accounts bereit, einschließlich Projekt-ID, Client-E-Mail, privatem Schlüssel und den zugehörigen OAuth-Endpoints. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "authProviderX509CertUrl": "https://www.googleapis.com/oauth2/v1/certs", "authUri": "https://accounts.google.com/o/oauth2/auth", "clientEmail": "", "clientId": "", "clientX509CertUrl": "https://www.googleapis.com/robot/v1/metadata/x509/", "name": "FCM Service Account", "privateKey": "", "privateKeyId": "", "projectId": "", "tokenUri": "https://oauth2.googleapis.com/token", "type": "service_account", "universeDomain": "googleapis.com" } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------------- | ------- | --------------------------------------------------------------------------------------- | | `authProviderX509CertUrl` | string | URL, über die die öffentlichen Zertifikate der Authentifizierung bereitgestellt werden. | | `authUri` | string | Standard-URL für das OAuth-Token-Handling bei Google. | | `clientEmail` | string | E-Mail-Adresse des Service-Accounts. | | `clientId` | string | Interne ID des Service-Accounts. | | `clientX509CertUrl` | string | URL, über die die öffentlichen Zertifikate der Authentifizierung bereitgestellt werden. | | `name` | string | Anzeigename des Service-Accounts im System. | | `privateKey` | string | Privater Schlüssel des Service-Accounts (dient zur Signierung der Token). | | `privateKeyId` | string | Schlüssel-ID des Service-Accounts (dient zur Signierung der Token). | | `projectId` | string | ID des zugehörigen Firebase-/Google-Cloud-Projekts. | | `tokenUri` | string | Standard-URLs für das OAuth-Token-Handling bei Google | | `type` | string | Typ des Authentifizierungsobjekts – hier immer `service_account`. | | `universeDomain` | string | Google-spezifischer Namespace (Standard: `googleapis.com`). | # b2b - Business-to-Business (B2B) Source: https://dokumentation.websale.de/konfiguration/b2b-business-to-business-b2b B2B-spezifische Shopkonfiguration im WEBSALE: Kundengruppen, Berechtigungen sowie Preislogik für Geschäftskunden über den Konfigurationsknoten b2b. B2B-spezifische Einstellungen (z. B. Gruppen, Berechtigungen, Preislogik). *** ## `b2b*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `b2b`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "b2b": { "access": {...}, "accountVerification": {...}, "userInvitation": {...} } } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | --------------------- | ---------------------------------------------------------------------------- | | `access` | Steuert die Zutrittsbeschränkungen. | | `accountVerification` | Steuert die Einladungs-E-Mail und Reminder-Logik bei der Kontoverifizierung. | | `userInvitation` | Steuert die Einladungs-E-Mail und zugehörige Reminder-Logiken. | *** ## `b2b.access` - Zutrittsbeschränkungen Konfiguriert die Zutrittsbeschränkungen für B2B-Kunden, z.B. nach der Registrierung vor einer manuellen Freischaltung durch den Händler. #### Beispielkonfiguration `b2b.access` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accessBeforeVerification": { "allowedTemplates": [ "account/accountManagement.htm" ], "allowedUrls": [], "redirectTarget": "error.htm", "restricted": false }, "allowedActions": [], "allowedTemplates": [], "allowedUrls": [], "redirectTarget": "error.htm", "restricted": false } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | -------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `accessBeforeVerification` | object | Steuert die Zugriffsbeschränkungen für Nutzer, die noch nicht verifiziert sind. | | `restricted` | bool | Schaltet die Zutrittsbeschränkung für nicht verifizierte Konten an (`true`) oder aus (`false`).
    Default: **false** | | `redirectTarget` | string | Name des Templates, auf das der Nutzer weitergeleitet wird, wenn er auf eine Seite zugreift, die den Login erfordert (z.B. `error.htm`). | | `allowedTemplates` | list (string) | Liste von Templates, die auch ohne Login aufgerufen werden dürfen (z.B. `account/accountManagement.htm`). | | `allowedUrls` | list (string) | Liste von URLs, die auch ohne Login aufgerufen werden dürfen. | | `restricted` | bool | Aktiviert die manuelle Kontoverifizierung.
    Der Kunde / die Firma kann sich selbst registrieren, ist aber bis zur Freischaltung durch den Händler eingeschränkt.
    Default: **false** | | `redirectTarget` | string | Name des Templates, auf das bei verweigertem Zugriff umgeleitet wird. (z.B. error.htm) | | `allowedTemplates` | list (string) | Liste von Templates, die vor der Verifizierung aufgerufen werden dürfen. | | `allowedUrls` | list (string) | Liste erlaubter Pfade, die vor der Verifizierung aufgerufen werden dürfen. (z.B. `/login`, `/register` ) | | `allowedActions` | list (string) | Liste erlaubter Aktionen, die trotz aktiver Beschränkung genutzt werden dürfen (z.B. **login, logout**).
    Bleibt die Liste leer, sind keine Aktionen explizit freigeschaltet. | *** ## `b2b.userInvitation` - Benutzereinladung Konfiguriert die E-Mail, mit der ein neuer Benutzer zu einem B2B-Firmenkonto eingeladen wird. Die Mail enthält einen Aktivierungslink, über den der eingeladene Nutzer das Konto aktiviert. Optional kann eine Erinnerungs-E-Mail versendet werden, solange die Einladung noch nicht angenommen wurde. Der Einladungslink ist für die in `invitationLinkValidityInHours`definierte Dauer gültig. Nach Ablauf muss die Einladung erneut versendet werden. Ist `reminderActive: true`, wird im Intervall von `reminderIntervallInDays` eine Erinnerungs-E-Mail an noch offene Einladungen versendet. **Beispielkonfiguration** `b2b.userInvitation` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": { "fromAddress": "", "fromName": "", "subject": "", "template": "" }, "invitationLinkValidityInDays": 1, "reminderActive": false, "reminderEmail": { "fromAddress": "", "fromName": "", "subject": "", "template": "" }, "reminderIntervalInDays": 7 } ``` **Parameterübersicht** | **Parameter** | **Typ** | **Beschreibung** | | ------------------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `email` | object | Konfiguration der initialen Einladungs-E-Mail. | | `fromAddress` | string | Absenderadresse, die im E-Mail-Versand versendet wird (z.B. `noreply@mein-shop.de`). | | `fromName` | string | Anzeigename des Absenders in der E-Mail (z.B. “Mein Onlineshop”). | | `subject` | string | Betreffzeile der E-Mail, wie sie im Posteingang des Kunden angezeigt wird. | | `template` | string | Name oder Pfad der zu verwendenden [E-Mail-Vorlage](/konfiguration/messages-ereignisgesteuerte-e-mails).
    Darüber werden Inhalt und Layout der E-Mail gesteuert. | | `invitationLinkValidityInDays` | int | Gültigkeitsdauer des Einladungslinks in Tagen. | | `reminderActive` | bool | Aktiviert (`true`) oder deaktiviert (`false`) den automatischen Versand
    von Erinnerungs-E-Mails an noch nicht angenommene Einladungen. | | `reminderEmail` | object | Konfiguration der Erinnerungs-E-Mail.
    Wird nur genutzt, wenn `reminderActive: true` | | `fromAddress` | string | E-Mail-Adresse, von der die Erinnerung gesendet wird. | | `fromName` | string | Absenderadresse, die im E-Mail-Versand versendet wird (z.B. `noreply@mein-shop.de`). | | `subject` | string | Betreff der Erinnerungs-E-Mail. | | `template` | string | Inhalt der Erinnerungs-E-Mail. | | `reminderIntervalInDays` | int | Intervall in Tagen, in dem Erinnerungen versendet werden, solange die Einladung offen und noch gültig ist. | *** ## `b2b.accountVerification` - Kontoverifizierung Konfiguriert den Verifizierungsprozess für B2B-Konten. Mit `requireEmailVerification` und `requireManualVerification` wird gesteuert, welche Art der Verifizierung erforderlich ist, während `verificationMerchantEmail` die E-Mails definiert, die bei Freischaltung bzw. Widerruf eines Kontos versendet werden. Mit `permissionsBeforeVerification` werden die Berechtigungen festgelegt, die ein noch nicht verifiziertes Konto im Shop hat. **Beispielkonfiguration** `b2b.accountVerification` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "requireEmailVerification": true, "requireManualVerification": false, "verificationMerchantEmail": { "fromAddress": "", "fromName": "", "subject": "", "template": "", "subjectForRevocation": "", "templateForRevocation": "" }, "permissionsBeforeVerification": { "viewProducts": true, "viewCategories": true, "viewPrices": false, "placeOrders": false } } ``` **Parameterübersicht** | Parameter | Typ | Beschreibung | | :------------------------------ | :----- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `requireEmailVerification` | bool | Legt fest, ob eine E-Mail-Verifizierung für neue B2B-Konten erforderlich ist. | | `requireManualVerification` | bool | Legt fest, ob neue B2B-Konten zusätzlich manuell durch den Händler freigegeben werden müssen. | | `verificationMerchantEmail` | object | Konfiguration der E-Mails bei Kontofreischaltung und -widerruf. | | `fromAddress` | string | Absenderadresse, die im E-Mail-Versand versendet wird (z.B. `noreply@mein-shop.de`). | | `fromName` | string | Anzeigename des Absenders in der E-Mail (z.B. “Mein Onlineshop”). | | `subject` | string | Betreffzeile der E-Mail, wie sie im Posteingang des Kunden angezeigt wird. | | `template` | string | Name oder Pfad der zu verwendenden [E-Mail-Vorlage](https://dokumentation.websale.de/konfiguration/messages-ereignisgesteuerte-e-mails).
    Darüber werden Inhalt und Layout der E-Mail gesteuert. | | `subjectForRevocation` | string | Betreffzeile der E-Mail bei Widerruf der Kontofreischaltung. | | `templateForRevocation` | string | Name oder Pfad der zu verwendenden [E-Mail-Vorlage](https://dokumentation.websale.de/konfiguration/messages-ereignisgesteuerte-e-mails) für die Widerrufs-E-Mail. | | `permissionsBeforeVerification` | object | Definiert, welche Aktionen ein noch nicht verifiziertes Konto im Shop ausführen darf. | | `viewProducts` | bool | Legt fest, ob Produkte für nicht verifizierte Konten sichtbar sind. | | `viewCategories` | bool | Legt fest, ob Kategorien für nicht verifizierte Konten sichtbar sind. | | `viewPrices` | bool | Legt fest, ob Preise für nicht verifizierte Konten sichtbar sind. | | `placeOrders` | bool | Legt fest, ob nicht verifizierte Konten Bestellungen aufgeben können.
    Bei `false` werden auch Warenkorb-Aktionen blockiert. | # basket - Warenkorb Source: https://dokumentation.websale.de/konfiguration/basket-warenkorb Konfiguration des basket-Knotens: Warenkorbverhalten, automatische Beigaben (autobasket), Warenkorb-Cookies und Speicherdauer im WEBSALE Onlineshop. Der Abschnitt `basket` umfasst alle Einstellungen rund um den Warenkorb des Onlineshops.
    Hier wird gesteuert, wie sich der Warenkorb verhält, welche Artikel automatisch hinzugefügt werden und wie lange Warenkorbdaten gespeichert bleiben. Zu den typischen Konfigurationsmöglichkeiten gehören: * **Beigaben** – definiert Produkte, die beim ersten Laden des Shops automatisch in den Warenkorb gelegt werden (z.B. Überraschungsprodukte) * **Warenkorb-Cookies** – legt fest, ob ein Cookie-basierter Warenkorb aktiv ist, wie lange er gespeichert bleibt und wie sich das System bei Rückkehr eines Nutzers verhält. * **Allgemeine Warenkorb-Optionen** – z. B. maximale Anzahl von Artikeln, Verhalten bei Preisänderungen oder Synchronisation zwischen Sitzungen. Der Warenkorb gilt immer nur innerhalb eines Subshops. Wie Sie die Positionen beim Wechsel in einen anderen Subshop mitnehmen können, erfahren Sie unter [Warenkorb beim Subshop-Wechsel mitnehmen](/frontend/referenz/module/wssubshop#warenkorb-beim-subshop-wechsel-mitnehmen). *** ## `basket*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `basket` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "basket": { "autobasket": { ... }, "basket": { ... } } } ``` #### Parameterbeschreibung | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `autobasket` | Automatisch hinzugefügte Warenkorb-Positionen.
    Enthält je Land / Shop eine Liste der Einträge. | | `basket` | Grundlegendes Warenkorbverhalten: Persistenz über Konto/Cookie, Gültigkeitsdauer, Verhalten bei Login/Logout, maximale Artikelmenge. | *** ## `basket.basket` - Einstellungen für den Warenkorb Der Knoten `basket` steuert das grundlegende Verhalten des Warenkorbs im Shop. Hier wird festgelegt, ob Warenkörbe benutzerbezogen gespeichert werden, wie lange Cookies gültig sind, und wie der Warenkorb beim Login oder Logout reagiert. Diese Einstellungen bestimmen also, wie dauerhaft ein Warenkorb erhalten bleibt und wie sich das System bei wiederkehrenden Nutzern verhält. Typische Anwendungsfälle: * Aktivierung eines persistenten Warenkorbs über Kundenkonto oder Cookie * Festlegung der Gültigkeitsdauer gespeicherter Warenkörbe * Steuerung, ob ein Warenkorb beim Logout gelöscht oder beibehalten wird * Begrenzung der maximalen Artikelmenge im Warenkorb #### Beispielkonfiguration für alle Subshops (`basket.basket`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountBasketActive": true, "accountBasketDurationDays": 365, "clearBasketOnLogout": false, "cookieBasketActive": false, "cookieBasketDurationDays": 30, "maxItemQuantity": 100, "readCookieBasketAfterLogin": false } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ---------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `accountBasketActive` | bool | Steuert, ob beim Login der zuletzt zum Benutzerkonto gespeicherte Warenkorb automatisch wiederhergestellt wird.
    Der aktuell genutzte Warenkorb bleibt auch ohne diese Option nach einem Logout lokal erhalten (z.B. per Session/Cookie).
    - `true` - Beim nächsten Login wird der kontogebundene, zuletzt gespeicherte Warenkorb serverseitig geladen.
    - `false` - Es erfolgt keine serverseitige Wiederherstellung; es bleibt nur die lokale Persistenz aktiv. Default: **false** | | `accountBasketDurationDays` | int | Gültigkeitsdauer eines gespeicherten Konto-Warenkorbs in Tagen. Nach Ablauf wird der Warenkorb automatisch gelöscht.
    Default: **365** | | `clearBasketOnLogout` | bool | Bestimmt, ob der Warenkorb beim Logout gelöscht wird (`true`) oder erhalten bleibt (`false`).
    Default: **false** | | `cookieBasketActive` | bool | Aktiviert den Cookie-basierten Warenkorb. Ist der Wert true, wird der Warenkorb auch ohne Login über ein Browser-Cookie gespeichert.
    Es können Konto-Warenkorb und Cookie-Warenkorb parallel existieren. Bei aktivem Login wird in der Regel der Konto-Warenkorb priorisiert.
    Durch Kombination von `cookieBasketActive` und `accountBasketActive` kann ein nahtloser Warenkorberhalt über Geräte hinweg ermöglicht werden.
    Default: **false** | | `cookieBasketDurationDays` | int | Gültigkeitsdauer des Cookie-Warenkorbs in Tagen. Nach Ablauf wird der Cookie-Warenkorb gelöscht.
    Default: **30** | | `maxItemQuantity` | float | Legt fest, wie viele Einzelartikel maximal in den Warenkorb gelegt werden dürfen. Dient zur Begrenzung übermäßiger Warenkorbgrößen.
    Default: **100.0** | | `readCookieBasketAfterLogin` | bool | Steuert, ob nach einem Login ein vorhandener Cookie-Warenkorb ausgelesen und mit dem Konto-Warenkorb zusammengeführt wird (`true`), oder ob er ignoriert wird (`false`).
    Default: **false** | *** ## `basket.autobasket` - Beigaben zum Warenkorb Mit `autobasket` lassen sich Artikel automatisch in den Warenkorb legen – z. B. Geschenkartikel oder Promo-Produkte. Mehrere automatische Artikel sind möglich; Reihenfolge entspricht der Konfiguration. Ohne Bedingungen werden die Positionen immer hinzugefügt; über optionale Bedingungen können Sie die automatische Beigabe steuern (z. B. pro Subshop, Land, Kampagne). #### Beispielkonfiguration für alle Subshops (`basket.autobasket`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "products": [ { "product": { "id": "GIFT-001", "variant": "std", "number": "900001" }, "behavior": { "product": true, "removable": true, "changeable": false } }, { "product": { "id": "DEPOSIT-250", "number": "990250" }, "conditions": [ { "field": "country", "value": "DE" } ], "behavior": { "product": true, "removable": false, "changeable": false } } ] } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | `products` | list (object) | Liste der Produkte, die dem Warenkorb hinzugefügt werden sollen. | | `product` | object | Jeder Eintrag beschreibt **einen** Artikel inkl. Identifikation, optionalen Bedingungen und Verhalten. | | `id` | string | Interne/technische Artikel-ID. | | `variant` | string | Variantenkennung (falls benötigt), z. B. Größe/Farbe. | | `number` | string | Artikelnummer (SKU). | | `conditions` | list (object) | Liste von Bedingungen; **alle** müssen erfüllt sein, damit die Beigabe hinzugefügt wird. | | `field` | string | Prüf-Feld (z. B. `country`, `subshop`, `campaign`). | | `value` | string | Erwarteter Wert (z. B. `DE`, `deutsch`, `spring-sale`). | | `behavior` | object | Verhalten im Warenkorb | | `visible` | bool | Kennzeichnet, ob die Position im Warenkorb sichtbar ist.
    Default: **true** | | `removable` | bool | Kennzeichnet, ob die Position im Warenkorb durch den Käufer entfernt werden darf.
    Default: **true** | | `changeable` | bool | Kennzeichnet, ob die Position im Warenkorb durch den Käufer geändert werden darf, z.B. Menge / Variante.
    Default: **true** | # checkout - Bestellablauf Source: https://dokumentation.websale.de/konfiguration/checkout-bestellablauf Der Konfigurationsknoten checkout steuert den Bestellprozess der Storefront: Gast- und Schnellbestellung, Zusatzfelder, Rundung, Gutscheinlogik, Mindermengenzuschlag, Versandarten und -gruppen, Paketverfolgung sowie Fehleranzeige. Der Abschnitt `checkout` umfasst alles, was den Bestellprozess in der Storefront steuert: von der einfachen Gast- oder Schnellbestellung über eigene Eingabefelder bis zur Rundung von Zwischensummen. Er ermöglicht zudem eine schnelle Artikelerfassung per Artikelnummer, prüft bei Bedarf Warenkorbinhalte gegen Regeln (z. B. Pflichtzubehör), verwaltet Versandarten inklusive Preislogik und bindet Paketverfolgung an. ## `checkout*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `checkout` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "checkout": { "checkout": {...}, "voucher": {...}, "voucherErrors": {...}, "directOrder": {...}, "productDependency": {...}, "bankInfoField": {...}, "shippingMethod": {...}, "shippingMethodGroup": {...}, "shipTrack": {...} } } ``` ### Parameterübersicht | **Parameter** | **Beschreibung** | | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `checkout` | Übergreifende Checkout-Einstellungen für den Bestellprozess. | | `voucher` | Einstellungen für die Gutscheinverwendung im Bestellprozess. | | `voucherErrors` | Fehlertexte für Gutscheine, die im Warenkorb keine Wirkung haben. Siehe [`checkout.voucherErrors`](#checkout-vouchererrors-fehlertexte-zu-wirkungslosen-gutscheinen). | | `directOrder` | Konfiguration für Direktbestellungen. | | `productDependency` | Regeln für Produktabhängigkeiten im Checkout. | | `bankInfoField` | Steuerung von Bankdatenfeldern. | | `shippingMethod` | Einstellungen zu Versandarten. | | `shippingMethodGroup` | Gruppen, zu denen Versandarten zusammengefasst werden können. | | `shipTrack` | Optionen für die Sendungsverfolgung. | ## `checkout.checkout` - Bestellablauf Dieser Abschnitt bündelt die zentralen Einstellungen des Bestellprozesses. Er richtet sich an Shop-Betreiber, die den Ablauf kaufmännisch festlegen, und an Frontend-Entwickler, die das Ergebnis im Template ausgeben. Vorausgesetzt wird, dass Sie mit dem grundsätzlichen [Bestellablauf](/frontend/funktionsubersicht/bestellablauf) vertraut sind. Festgelegt wird hier, wie der Bestellprozess abläuft, welche Zusatzfelder erscheinen und wie Versand- und Zahlungsarten vorausgewählt werden. Ebenfalls hier angesiedelt sind die Regeln für Gutschein-Berechnungen, ein Mindermengenzuschlag, die Behandlung von Adressen aus dem PayPal Express Checkout und der Zeitpunkt, ab dem Feldfehler sichtbar werden. Nicht in diesem Abschnitt behandelt: Versandarten und deren Preislogik stehen unter [`checkout.shippingMethod`](#checkout-shippingmethod-versandarten), die Rundung von Gutscheinbeträgen unter [`checkout.voucher`](#checkout-voucher-einstellungen-fur-gutscheine), die Fehlertexte zu wirkungslosen Gutscheinen unter [`checkout.voucherErrors`](#checkout-vouchererrors-fehlertexte-zu-wirkungslosen-gutscheinen), Zahlungsarten unter `payment.payment`. Die Einstellungen wirken an vier verschiedenen Stellen im Ablauf. Diese Einordnung hilft beim Finden des passenden Parameters: * **Vor der Bestellung - Zugang und Vorauswahl:** Wer darf bestellen (`allowGuestAccounts`, `allowFastOrder`), was ist vorausgewählt (`defaults`), welche Zusatzfelder erscheinen (`freeFields`). * **Während der Bestellung - Berechnung:** Rundung der Zwischensumme (`subtotalRounding`), Gutschein-Verrechnung (`voucherAppliesPerItem`, `minOrderValueCalculation`, `minOrderValueIgnoreVoucherReduction`, `disableOrderOnIneffectiveVoucher`) und der Mindermengenzuschlag (`surcharge`). * **Während der Bestellung - Anzeige von Fehlern:** `fieldErrorVisibility`. * **Nach der Bestellung:** welche Templates noch auf die Bestelldaten zugreifen dürfen (`templatesAfterCheckout`). Nachfolgend eine Beispielkonfiguration für `checkout.checkout`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "allowFastOrder": true, "allowGuestAccounts": true, "allowShipTrack": false, "defaults": { "defaultBillCountry": null, "defaultShippingCountry": null, "defaultPaymentMethod": null, "defaultShippingMethod": null, "autoSelectSingleOption": true, "prevSelectionInvalidAutoSelect": "disabled" }, "defaultFreeShippingMethod": null, "deliveryRequiredForOrder": true, "disableOrderOnIneffectiveVoucher": true, "expressCheckoutSkipsAddressValidation": true, "fieldErrorVisibility": { "showMissingBeforeSubmit": false, "showInvalidBeforeSubmit": true, "showIncompatibleBeforeSubmit": true }, "freeFields": [...], "freeShippingCountries": null, "minOrderValueCalculation": "max", "minOrderValueIgnoreVoucherReduction": true, "subtotalRounding": { "active": true, "decimalPlaces": 2 }, "surcharge": { "cost": 1.99, "threshold": 30.0 }, "templatesAfterCheckout": [ "pdf/checkoutConfirm.htm" ], "voucherAppliesPerItem": true } ``` ### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------------------------------------------------------------------------------------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `allowGuestAccounts` | bool | Erlaubt Bestellungen ohne Kundenkonto (Gastbestellung).
    Default: `true` | | `allowFastOrder` | bool | Erlaubt die Bestellung per Express-Checkout.
    Default: `true` | | `allowShipTrack` | bool | Aktiviert die Sendungsverfolgung für den Shop. Die Zugangsdaten des Dienstleisters werden unter [`checkout.shipTrack`](#checkout-shiptrack-paketverfolgung) hinterlegt.
    Default: `false` | | `deliveryRequiredForOrder` | bool | Gibt vor, ob eine Versandart ausgewählt sein muss, damit die Bestellung abgeschlossen werden kann.
    `true` - Checkout nur mit gewählter Versandart möglich.
    `false` - Bestellung ohne Auswahl einer Versandart zulässig.
    Default: `true` | | `subtotalRounding` | object | Rundung der Zwischensumme vor weiteren Berechnungen (z.B. vor Versand / Gutscheinen). | | `active` | bool | Aktiviert die Rundungslogik.
    Default: `true` | | `decimalPlaces` | uint | Anzahl der Nachkommastellen für die Rundung.
    Default: `2` | | `voucherAppliesPerItem` | bool | Steuert, ob Gutscheine pro Position (statt auf den Gesamtwarenkorb) angewendet werden.
    Default: `false` | | `minOrderValueCalculation` | enum | Legt fest, wie der Mindestbestellwert berechnet wird, ab dem ein Gutschein angewendet werden kann.
    Mögliche Werte:
    `sum` - die Mindestbestellwerte aller verwendeten Gutscheine werden addiert. Hat z.B. Gutschein A einen Mindestbestellwert von 20€ und Gutschein B von 30€, muss der Warenkorb mindestens 50€ erreichen.
    `max` - es gilt nur der höchste Mindestbestellwert aller verwendeter Gutscheine. Bei Gutschein A (20€) und Gutschein B (30€) reichen 30€ im Warenkorb aus.
    Default: `sum` | | `minOrderValueIgnoreVoucherReduction` | bool | Bestimmt, welcher Warenwert für die Prüfung des Mindestbestellwertes herangezogen wird.
    Mögliche Werte:
    `true` - nur der reine Warenwert zählt.
    `false` - der Warenwert abzüglich bereits angewandter Gutscheine wird verwendet.
    Default: `true` | | `disableOrderOnIneffectiveVoucher` | bool | Sperrt die Bestellung, solange ein eingelöster Gutschein im aktuellen Warenkorb keinen Rabatt bewirkt. Der Default `true` verhindert, dass ein Kunde in der Annahme bestellt, ein Rabatt greife.
    Wann ein Gutschein als wirkungslos gilt, steht unter [Wirkungslose Gutscheine blockieren](#wirkungslose-gutscheine-blockieren).
    Default: `true` | | `surcharge` | object | Mindermengenzuschlag für kleine Warenkörbe. Siehe [Mindermengenzuschlag](#mindermengenzuschlag). | | `cost` | float | Zuschlagsbetrag in Shop-Währung, der berechnet wird, wenn der Schwellenwert nicht überschritten wird.
    Default: `0.0` | | `threshold` | float | Schwellenwert: Übersteigt die Summe der zuschlagspflichtigen Positionen diesen Wert, entfällt der Zuschlag. Mit dem Default `0.0` ist der Zuschlag praktisch abgeschaltet, da jeder Warenkorb mit Wert darüber liegt.
    Default: `0.0` | | `expressCheckoutSkipsAddressValidation` | bool | Steuert, ob die vom PayPal Express Checkout gelieferte Adresse als reguläre Rechnungs- und Lieferadresse übernommen und gegen die Prüfregeln des Shops geprüft wird. Siehe [Adressen aus dem PayPal Express Checkout](#adressen-aus-dem-paypal-express-checkout).
    Default: `true` | | `templatesAfterCheckout` | list (string) | Templates, die nach dem Bestellabschluss noch auf die Bestelldaten zugreifen dürfen. Siehe [Templates nach dem Bestellabschluss](#templates-nach-dem-bestellabschluss).
    Default: `[]` | | `fieldErrorVisibility` | object | Legt fest, ab wann Feldfehler im Checkout angezeigt werden. Siehe [Fehleranzeige im Checkout](#fehleranzeige-im-checkout). | | `showMissingBeforeSubmit` | bool | Zeigt fehlende Pflichtfelder bereits vor dem Klick auf „Kaufen".
    Default: `false` | | `showInvalidBeforeSubmit` | bool | Zeigt Validierungsfehler bereits vor dem Klick auf „Kaufen".
    Default: `true` | | `showIncompatibleBeforeSubmit` | bool | Zeigt Inkompatibilitätsfehler bereits vor dem Klick auf „Kaufen".
    Default: `true` | | `freeShippingCountries`
    (**zukünftiges Feature,**
    **noch nicht vollständig**
    **implementiert!**) | multiAssoc | Länder, in denen versandkostenfrei geliefert wird.
    Target: `general.country` | | `defaultFreeShippingMethod` | singleAssoc | Legt die Standard-Versandart fest, die für Berechnungen zu „kostenlosem Versand" verwendet wird (z.B. Anzeige „noch 45€ bis zum kostenlosen Versand").
    Target: `checkout.shippingMethod` | | `freeFields` | list (object) | Konfigurierbare Zusatzfelder im Checkout (z.B. Hinweise, Kundennotizen, AGB-Bestätigung). Jedes Objekt beschreibt ein Feld. | | `id` | string | Eindeutige Kennung des Zusatzfeldes. Über diese Kennung lesen Sie das Feld im Template aus `$wsCheckout.freeFields`. | | `name` | text | Anzeigename / Label im Checkout. | | `required` | bool | Markiert das Feld als Pflichtfeld.
    Default: `false` | | `type` | oneOf | Feldtyp und Detailkonfiguration: `text` oder `checkbox`. | | `text` | object | Textfeld-Konfiguration. | | `default` | string | Vorbelegung des Textfeldes. | | `textfieldChecks` | multiService | Prüfregeln für die Eingabe.
    Target: `dataChecker` | | `checkbox` | object | Checkbox-Konfiguration. | | `default` | bool | Legt fest, ob die Checkbox vorausgewählt ist.
    Default: `false` | | `merchantText` | string | Interner Text zur Checkbox für den Händler. | | `defaults` | object | Definiert Standardwerte für Felder im Checkout. | | `defaultBillCountry` | singleAssoc | Standardland für die Rechnungsadresse. Wird beim Anlegen einer neuen Adresse im Checkout vorausgefüllt - bei Nutzung der Draft-Adresse ([draftBillAddress](/frontend/referenz/aktionen/checkout)) sowie bei Gastbestellungen.
    Target: `general.country` | | `defaultShippingCountry` | singleAssoc | Standardland für die Lieferadresse. Wird beim Anlegen einer neuen Adresse im Checkout vorausgefüllt - bei Nutzung der Draft-Adresse ([draftShippingAddress](/frontend/referenz/aktionen/checkout)) sowie bei Gastbestellungen.
    Target: `general.country` | | `defaultPaymentMethod` | singleAssoc | Zahlungsart, die im Checkout standardmäßig vorausgewählt wird.
    Target: `payment.payment` | | `defaultShippingMethod` | singleAssoc | Liefermethode, die im Checkout standardmäßig vorausgewählt wird.
    Target: `checkout.shippingMethod` | | `autoSelectSingleOption` | bool | Wenn aktiviert, wird automatisch eine Versandmethode oder Zahlungsart ausgewählt, sofern nur eine gültige Option verfügbar ist. Das erspart dem Kunden eine Auswahl ohne Alternative.
    Default: `true` | | `prevSelectionInvalidAutoSelect` | enum | Steuert, ob eine bereits gewählte Versand- oder Zahlungsart automatisch ersetzt wird, wenn sie durch eine Änderung des Bestellkontexts (z.B. Wechsel des Lieferlandes) ungültig wird. Gilt für Versand- und Zahlungsarten (keine getrennte Option je Art).
    Mögliche Werte:
    `disabled` - keine automatische Neuauswahl durch diese Option; die Auswahl wird als ungültig markiert und der Kunde wählt neu (`autoSelectSingleOption` greift weiterhin).
    `ifSingleOption` - bleibt genau eine gültige Art übrig, wird diese automatisch gewählt (auch wenn `autoSelectSingleOption` deaktiviert ist); bleiben mehrere gültig, erfolgt keine automatische Auswahl.
    `always` - es wird immer eine gültige Ersatz-Art gewählt: bevorzugt die konfigurierte Standard-Art (`defaultShippingMethod` bzw. `defaultPaymentMethod`), sofern gültig; andernfalls die einzige verbleibende gültige Art.
    Der Default `disabled` ist die zurückhaltendste Variante: eine bewusste Kundenauswahl wird nie stillschweigend gegen eine andere getauscht.
    Default: `disabled` | Ob eine Gastbestellung mit einer bereits registrierten E-Mail-Adresse erlaubt ist, wird nicht hier festgelegt, sondern in der Konfiguration der Aktion `CheckoutSetGuestEmail` unter `restrictions.allowGuestOrderWithRegisteredEmail`. **Prioritätslogik für** `defaults`: Wenn mehrere Quellen (z.B. Benutzerauswahl oder Kundenpräferenzen) einen Wert für ein Feld in `defaults` liefern, gilt folgende Rangfolge der Priorisierung: 1. Aktive Benutzerauswahl in der aktuellen Sitzung - wird niemals automatisch überschrieben. 2. Gespeicherte Kundenpräferenzen eines eingeloggten Kunden (sofern unterstützt). 3. Händler-Konfiguration - die hier definierten `defaults`-Werte. 4. System-Fallback - z.B. automatische Auswahl bei nur einer verfügbaren Option oder erste gültige Option nach Sortierung (siehe `autoSelectSingleOption`). Neuauswahl, wenn eine gewählte Art nachträglich ungültig wird: Die Prioritätslogik oben gilt für die Erstauswahl. Wird dagegen eine bereits getroffene, aber inzwischen ungültige Auswahl behandelt - etwa weil der Kunde das Lieferland wechselt und die gewählte Versandart dort nicht angeboten wird -, steuert `prevSelectionInvalidAutoSelect`, wie der Shop reagiert (siehe Tabelle oben). `autoSelectSingleOption` bleibt dabei in allen Modi als Rückfallebene aktiv. Hinweis zum Rundungsverhalten bei positionsbasierter Gutschein-Berechnung:
    Wenn „`voucherAppliesPerItem`" auf „`true`" gesetzt ist und ein prozentualer Gutschein mit einem konfigurierten Maximalbetrag verwendet wird, kann der gewährte Rabatt diesen Maximalbetrag um bis zu 0,01 € überschreiten. Grund dafür ist, dass der Rabatt pro Position einzeln gerundet wird und die Summe dieser Rundungen minimal vom erwarteten Gesamtbetrag abweichen kann.
    ### Mindermengenzuschlag Der Mindermengenzuschlag ist ein fester Betrag, der auf kleine Warenkörbe aufgeschlagen wird. Damit deckt der Shop die Bearbeitungs- und Versandkosten, die bei einer Kleinbestellung anteilig zu hoch ausfallen. Der Shop berechnet den Zuschlag bei jeder Warenkorb-Berechnung neu, in dieser Reihenfolge: 1. Der Shop bildet die Summe der zuschlagspflichtigen Positionen. Gezählt wird die Positionssumme, also Preis mal Menge. Unterpositionen eines Sets zählen nicht mit, weil sie sonst doppelt in die Summe eingehen würden. 2. Enthält der Warenkorb keine zuschlagspflichtige Position, fällt kein Zuschlag an. 3. Übersteigt die Summe den Wert `threshold`, fällt kein Zuschlag an. 4. Andernfalls wird `cost` als Zuschlag berechnet. Der Vergleich in Schritt 3 ist ein „größer als". Bei `"threshold": 30` und einer Summe von genau 30,00 € fällt der Zuschlag also noch an, ab 30,01 € nicht mehr. Setzen Sie den Schwellenwert entsprechend auf den letzten Betrag, für den noch zugeschlagen werden soll. Standardmäßig ist jede Position zuschlagspflichtig. Ausnehmen können Sie einzelne Produkte über das Produktfeld, das unter `content.usedFields.validForSurcharge` hinterlegt ist: Liefert dieses Feld für eine Position `false`, zählt sie weder für die Prüfung mit, noch löst sie den Zuschlag aus. Das ist etwa für Gutscheinprodukte oder digitale Artikel sinnvoll, die keinen Bearbeitungsaufwand verursachen. Ein Beispiel: Ein Zuschlag von 1,99 € soll bis zu einem Warenwert von 30 € anfallen. Die Konfiguration in `checkout.checkout` lautet dann: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "surcharge": { "cost": 1.99, "threshold": 30.0 } } ``` Ausgabe in der Kostenaufstellung des Templates. Der Zuschlag steht als berechneter Betrag in `$wsCheckout.sum.surchargeCost`; ist er `0`, wird die Zeile nicht ausgegeben: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.sum.surchargeCost > 0 }} Mindermengenzuschlag {{= $wsCheckout.sum.surchargeCost | currency }} {{ /if }} ``` Erwartete Wirkung: Bei einem Warenkorb von 24,50 € erscheint die Zeile mit 1,99 €, und die Gesamtsumme steigt auf 26,49 €. Bei einem Warenkorb von 45,00 € entfällt die Zeile. ### Wirkungslose Gutscheine blockieren Ein Kunde kann einen Gutschein einlösen, der im aktuellen Warenkorb gar keinen Rabatt bewirkt. Bestellt er in diesem Zustand, entsteht eine Rückfrage oder Reklamation, weil der erwartete Rabatt fehlt. `disableOrderOnIneffectiveVoucher` verhindert das. Der Ablauf: 1. Der Kunde löst einen Gutschein ein. Der Gutschein liegt in der Session. 2. Bei jeder Berechnung prüft der Shop für jeden eingelösten Gutschein, ob er im aktuellen Warenkorb einen Rabatt größer `0` erzeugt. 3. Als wirkungslos gilt ein Gutschein in zwei Fällen: Der Warenkorb erreicht den Mindestbestellwert nicht, oder der berechnete Rabatt ist `0`, weil keine Position im Warenkorb für diesen Gutschein rabattfähig ist. Welcher der beiden Fälle vorliegt, ist im Template auswertbar. Die genauen Regeln stehen unter [Wann welcher Fehler entsteht](#wann-welcher-fehler-entsteht). 4. Reine Versandkosten-Gutscheine ohne Prozent- und ohne Absolutwert sind davon ausgenommen. Sie wirken über die Versandkosten und blockieren die Bestellung nie. 5. Ist `disableOrderOnIneffectiveVoucher` aktiv und mindestens ein Gutschein wirkungslos, meldet der Shop die Bestellung als gesperrt. Im Template lesen Sie den Zustand über das Flag `$wsCheckout.isOrderBlockedByIneffectiveVoucher` und deaktivieren den Bestellbutton. Über die Liste `$wsCheckout.ineffectiveVoucherErrors` nennen Sie dem Kunden zusätzlich den Grund und den betroffenen Gutschein: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $wsCheckout.isOrderBlockedByIneffectiveVoucher }}
    Gutscheine können nicht eingelöst werden:
      {{ foreach $cError in $wsCheckout.ineffectiveVoucherErrors }}
    • {{ if $cError.details.voucherId }} Gutschein {{= $cError.details.voucherId }}: {{ /if }} {{= $cError.text | ifNull($cError.code) }}
    • {{ /foreach }}
    {{ else }} {{ /if }} ``` Erwartete Wirkung: Nach dem Einlösen eines Gutscheins mit 50 € Mindestbestellwert in einen Warenkorb über 20 € wird der Bestellbutton deaktiviert, und der Hinweis nennt den Gutschein samt Grund. Nach dem Auffüllen des Warenkorbs über 50 € ist der Button wieder aktiv, und die Liste ist leer. Die ausgegebenen Texte pflegen Sie nicht hier, sondern im Konfigurationsknoten [`checkout.voucherErrors`](#checkout-vouchererrors-fehlertexte-zu-wirkungslosen-gutscheinen). Den Aufbau der einzelnen Fehlerobjekte finden Sie in der Modul-Referenz unter [`$wsCheckout.ineffectiveVoucherErrors`](/frontend/referenz/module/wscheckout#wscheckout-ineffectivevouchererrors). Setzen Sie den Parameter nur dann auf `false`, wenn Kunden in Ihrem Shop bewusst Gutscheine im Warenkorb liegen lassen dürfen, ohne dass diese wirken. ### Adressen aus dem PayPal Express Checkout Startet ein Kunde den PayPal Express Checkout aus dem Warenkorb, liefert PayPal die dort hinterlegte Adresse zurück. Diese Adresse erfüllt die Prüfregeln Ihres Shops nicht immer - etwa weil PayPal keine Hausnummer getrennt übergibt. `expressCheckoutSkipsAddressValidation` legt fest, wie der Shop damit umgeht. **`true` (Default):** Der Shop prüft die Adresse nicht und übernimmt sie nicht als Rechnungs- oder Lieferadresse der Bestellung. Sie bleibt in der Session und steht in den Bestelldaten unter `paypalCheckout.rawAddress`. Drittsysteme können sie dort auslesen und bei Bedarf selbst weiterverarbeiten. Der Default `true` hält damit die Adressdaten des Shops frei von ungeprüften Fremddaten - die Lieferadresse im Shop bleibt sauber. **`false`:** Die Adresse wird direkt von PayPal als normale Adresse übernommen. Dann muss sie auch die Prüfregeln des Shops erfüllen. Da sie ungeprüft aus dem PayPal-Konto stammt, kann es passieren, dass sie diesen Regeln nicht entspricht. In diesem Fall muss der Kunde die Adresse vor dem Bestellabschluss bearbeiten - der Express Checkout verliert damit seinen Vorteil, ohne zusätzlichen Eingabeschritt abschließbar zu sein. Unabhängig von dieser Einstellung werden die Adressdaten dem Kunden angezeigt, soweit PayPal sie liefert. Übergibt PayPal beispielsweise keine Straße, wird auch keine Straße angezeigt. Ausschnitt aus den Bestelldaten bei aktivem Parameter: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "paypalCheckout": { "expressCheckout": "true", "rawAddress": { "...": "von PayPal geliefertes Adressobjekt" } } } ``` Bei aktivem Parameter enthalten die regulären Adressfelder der Bestellung keine Adresse aus dem Express Checkout. Es kann also eine Bestellung ohne reguläre Adressdaten entstehen. Ob eine solche Bestellung weiterverarbeitet werden kann, hängt vom angebundenen Connector ab. Prüfen Sie das, bevor Sie den Express Checkout produktiv nehmen. `true` ist der Standardweg für den PayPal Express Checkout: Der Shop prüft die Adresse nicht und übernimmt sie nicht. Deaktivieren Sie den Parameter nur nach Prüfung, denn Auswirkungen auf den Express Checkout selbst sind nicht auszuschließen. Die Anforderungen von PayPal an diesen Ablauf bildet diese Dokumentation nicht ab - klären Sie sie bei Bedarf direkt mit PayPal. ### Templates nach dem Bestellabschluss Nach dem Bestellabschluss gilt die Session als beendet. Die Bestelldaten stehen dann nur noch den Templates zur Verfügung, die zur Bestellbestätigung zählen. Ruft der Kunde ein anderes Template auf, erhält er eine neue Session. In dieser neuen Session sind die Bestelldaten nicht mehr erreichbar. Das ist beabsichtigt: Eine abgeschlossene Bestell-Session soll nicht länger als nötig weiterleben. Die Zielseite nach dem Checkout ist automatisch enthalten. Jedes weitere Template, das Bestelldaten braucht, müssen Sie in `templatesAfterCheckout` eintragen - typischerweise eine PDF-Bestellbestätigung: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "templatesAfterCheckout": [ "pdf/checkoutConfirm.htm" ] } ``` Erwartete Wirkung: Ohne diesen Eintrag ist die PDF-Bestellbestätigung leer, weil `$wsCheckout.orderId` und die übrigen Bestelldaten in der neuen Session fehlen. Mit dem Eintrag werden Bestellnummer, Positionen und Summen ausgegeben. Fehlende Bestelldaten auf einer Folgeseite nach dem Checkout sind deshalb fast immer ein fehlender Eintrag in dieser Liste. ### Fehleranzeige im Checkout Nicht jeder Fehler soll dem Kunden sofort gezeigt werden. Ein leeres Pflichtfeld rot zu markieren, bevor der Kunde es überhaupt erreicht hat, wirkt wie ein Fehler des Kunden. Eine falsch formatierte Postleitzahl dagegen sollte er sofort korrigieren können. `fieldErrorVisibility` trennt diese Fälle nach Fehlerart. | **Parameter** | **Typ** | **Beschreibung** | | ------------------------------ | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `showMissingBeforeSubmit` | bool | Wenn `true`, werden „Pflichtfeld fehlt"-Felder bereits angezeigt, bevor der Kunde auf „Kaufen" klickt.
    Wenn `false`, erscheinen diese erst nach dem Klick auf „Kaufen". Der Default `false` vermeidet, dass noch unbearbeitete Felder als Fehler erscheinen.
    Default: `false` | | `showInvalidBeforeSubmit` | bool | Wenn `true`, werden Validierungsfehler (z.B. ungültige PLZ, fehlerhaftes Datumsformat) sofort nach der Eingabe angezeigt.
    Wenn `false`, erscheinen diese erst nach dem Klick auf „Kaufen". Der Default `true` erlaubt die Korrektur, während der Kunde noch im Feld ist.
    Default: `true` | | `showIncompatibleBeforeSubmit` | bool | Wenn `true`, werden Inkompatibilitätsfehler (z.B. Zahlart für dieses Land nicht verfügbar) sofort angezeigt.
    Wenn `false`, erscheinen diese erst nach dem Klick auf „Kaufen". Der Default `true` verhindert, dass der Kunde den Checkout mit einer Kombination fortsetzt, die ohnehin scheitert.
    Default: `true` | Nach dem Klick auf „Kaufen" werden standardmäßig alle Fehler angezeigt, unabhängig von dieser Einstellung. Im Checkout gibt es grundsätzlich zwei Arten von Fehlern: * Fehler, die das System selbst erkennt (z.B. „Pflichtfeld leer", „ungültige PLZ"):
    Diese werden über [\$wsCheckout.problems.\*](/frontend/referenz/module/wscheckout) bereitgestellt und lassen sich vollständig über die `show*BeforeSubmit`-Parameter steuern. * Fehler, die der Server zurückmeldet (z.B. nach dem Klick auf „Kaufen"):
    Hier greifen die Einstellungen der `show*BeforeSubmit`-Parameter nur teilweise. Bei Kundendaten und [Draft-Adressen](/frontend/referenz/aktionen/checkout) steht `$wsCheckout.problems.*` nicht zur Verfügung, deshalb werden die Serverfehler dort stattdessen über die `show*BeforeSubmit`-Parameter gefiltert. In allen anderen Bereichen des Checkouts (z.B. bei der Zahlungsart) werden Serverfehler immer sofort angezeigt, unabhängig von der Konfiguration.
    ## `checkout.voucher` - Einstellungen für Gutscheine In diesem Abschnitt werden die Einstellungen für die Verwendung von Gutscheinen im Bestellprozess gebündelt. Hier wird unter anderem festgelegt, wie viele Gutscheine ein Kunde gleichzeitig einlösen kann und wie Rabattbeträge bei prozentualen Gutscheinen rechnerisch gerundet werden. Nachfolgend eine Beispielkonfiguration für `checkout.voucher`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "maxNumberVouchersPerOrder": 1, "roundPercentalVoucherInBasketItem": "single" } ``` ### Parameterübersicht | Parameter | Typ | Beschreibung | | ----------------------------------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `maxNumberVouchersPerOrder` | uint | Maximale Anzahl an Gutscheinen, die pro Bestellung angewandt werden können.
    Mögliche Werte: `1` - `20`
    Default: `1` | | `roundPercentalVoucherInBasketItem` | enum | Legt fest, wie Rabattbeträge aus prozentualen Gutscheinen pro Artikel gerundet werden, wenn mehrere Gutscheine gleichzeitig aktiv sind.
    Mögliche Werte:
    `sum` - Der Rabatt jedes einzelnen Gutscheins wird pro Artikel zunächst ungerundet berechnet. Alle Rabattbeträge werden addiert und das Ergebnis erst am Ende gerundet.
    `single` - Der Rabattbetrag jedes Gutscheins wird pro Artikel sofort einzeln gerundet. Weil jede Rundung einen kleinen Fehler einführen kann, weicht die Gesamtersparnis je nach Artikelpreis und Gutscheinhöhe um wenige Cent vom `sum`-Ergebnis ab. | ## `checkout.voucherErrors` - Fehlertexte zu wirkungslosen Gutscheinen Ein eingelöster Gutschein kann im aktuellen Warenkorb wirkungslos sein. Damit der Kunde nicht nur einen allgemeinen Hinweis liest, sondern den konkreten Grund erfährt, pflegen Sie in diesem Knoten je Fehlerfall einen eigenen Text. Der Shop übersetzt den passenden Text und stellt ihn im Template über [`$wsCheckout.ineffectiveVoucherErrors`](/frontend/referenz/module/wscheckout#wscheckout-ineffectivevouchererrors) bereit. Der Knoten enthält ausschließlich Texte. Ob eine Bestellung mit einem wirkungslosen Gutschein tatsächlich blockiert wird, steuert `disableOrderOnIneffectiveVoucher` unter [Wirkungslose Gutscheine blockieren](#wirkungslose-gutscheine-blockieren). Nachfolgend eine Beispielkonfiguration für `checkout.voucherErrors`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "ineffectiveVoucherErrorCodes": { "noValidProducts": "", "minOrderValueNotReached": "" } } ``` ### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------------------ | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ineffectiveVoucherErrorCodes` | object | Bündelt die Fehlertexte für Gutscheine, die im Warenkorb keine Wirkung haben. | | `noValidProducts` | string | Fehlermeldung, die ausgegeben wird, wenn der Gutschein auf keine Position im Warenkorb anwendbar ist. Das tritt beispielsweise auf, wenn der Gutschein nur für bestimmte Produkte oder Kategorien gilt und keine davon im Warenkorb liegt, oder wenn keine Position im Warenkorb rabattfähig ist.
    Default: `ws.error.checkout.ineffectiveVoucherNoValidProducts`

    | | `minOrderValueNotReached` | string | Fehlermeldung, die ausgegeben wird, wenn der Mindestbestellwert für den Gutschein unterschritten ist.
    Default: `ws.error.checkout.ineffectiveVoucherMinOrderValueNotReached`

    | ### Wann welcher Fehler entsteht Der Shop ermittelt die Fehler bei jeder Berechnung neu, einmal pro eingelöstem Gutschein. Welcher der beiden Codes gesetzt wird, entscheidet sich in dieser Reihenfolge: 1. **Mindestbestellwert des einzelnen Gutscheins.** Liegt der Mindestbestellwert eines Gutscheins über dem Prüfwert des Warenkorbs, entsteht `minOrderValueNotReached` für genau diesen Gutschein. Als Prüfwert gilt der Warenwert. Steht `minOrderValueIgnoreVoucherReduction` auf `false`, wird der Warenwert vorher um die bereits angerechneten Gutscheinwerte reduziert. 2. **Rabattwirkung im Warenkorb.** Erreicht der Warenkorb den Mindestbestellwert und bleibt der berechnete Rabatt trotzdem `0`, entsteht `noValidProducts` für diesen Gutschein. 3. **Summe der Mindestbestellwerte.** Steht `minOrderValueCalculation` auf `sum` und erreichen alle Gutscheine ihren jeweils eigenen Mindestbestellwert, muss der Warenkorb zusätzlich die Summe aller Mindestbestellwerte erreichen. Wird sie nicht erreicht, entsteht `minOrderValueNotReached` genau einmal. Dieser Fehler lässt sich keinem einzelnen Gutschein zuordnen und enthält deshalb keine Gutschein-ID. Reine Versandkosten-Gutscheine ohne Prozent- und ohne Absolutwert erzeugen keinen dieser Fehler. Weil der Fehler aus Schritt 3 ohne Gutschein-ID kommt, prüfen Sie im Template immer erst, ob `details.voucherId` gesetzt ist, bevor Sie die ID ausgeben. Ein vollständiges Beispiel dazu finden Sie unter [Praxisbeispiele - Gutscheine](/gutscheine). ## `checkout.directOrder` - Onlinebestellschein Ermöglicht eine schnelle Erfassung von Artikeln per Artikelnummer - beispielsweise für große oder wiederkehrende Bestellungen. Festgelegt wird, welche Spalten pro Zeile sichtbar sind (z.B. Artikelnummer, Menge). Auf Wunsch merkt sich das System die zuletzt verwendete Zeilenanzahl über `saveCountInSession`. Nachfolgend eine Beispielkonfiguration für `checkout.directOrder`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "fields": [ "content.productField.id", "content.productField.itemNumber" ], "initialNumber": 5, "itemNumberFields": [], "maximalNumber": 1000, "refreshedNumber": 1, "saveCountInSession": true } ``` ### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | -------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `fields` | multiAssoc | Legt fest, in welchen Produktfeldern gesucht wird, um ein Produkt zu finden (z.B. `content.productField.id, content.productField.itemnumber).`
    Beispiel: Wenn `id` oder `itemNumber` konfiguriert sind, kann der Nutzer entweder die Produkt-ID oder die Artikelnummer eingeben.
    Target: `[content.productField], [content.customProductField]` | | `initialNumber` | int | Anzahl der Zeilen, die beim ersten Laden sichtbar sind.
    Default: **5** | | `itemNumberFields` | list (object) | Eingabefelder pro Zeile für die Artikelnummer-Erfassung - definiert Spalten / Felder und Beschriftungen (z.B. Reihenfolge, Label, Platzhalter). | | `maximalNumber` | int | Obergrenze der insgesamt zulässigen Eingabezeilen.
    Default: **1000** | | `refreshedNumber` | int | Anzahl der verfügbaren Zeilen, die bei Klick auf den Button “Zeilen hinzufügen” hinzugefügt werden.
    Default: **5** | | `saveCountInSession` | bool | Speichert die aktuelle Zeilenanzahl in der Session, damit sie beim nächsten Aufruf wiederhergestellt wird.
    default: **true** | ## `checkout.productDependency` - Produktabhängigkeiten Dieser Abschnitt legt fest, wann bestimmte Schritte oder Optionen im Checkout erlaubt sind. Er prüft dazu die Inhalte des Warenkorbs - etwa Eigenschaften wie Größe, Farbe oder ob ein Zusatzfeld ausgefüllt ist - und kann bei Nichterfüllung einen Hinweis anzeigen oder die Aktion sperren. Typische Einsatzfälle sind beispielsweise Pflichtzubehör oder das Verhindern verbotener Kombinationen im Checkout. Nachfolgend eine Beispielkonfiguration für `checkout.productDependency`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "", "disabledText": "", "dependencyGroups": [ { "dependencies": [ { "target": { "field": "content.productField:color" }, "type": "value", "input": { "text": { "value": "camel" } }, "basketBehavior": "matchOnce" }, { "target": { "freeField": "engraving" }, "type": "empty", "input": { "text": { "value": "" } }, "basketBehavior": "matchOnce" } ] }, { "dependencies": [ { "target": { "field": "content.customProductField:size" }, "type": "inlist", "input": { "list": { "value": ["S", "M", "L"] } }, "basketBehavior": "matchOnce" } ] } ] } ``` ### Auswertungslogik Die Regelgruppen und Bedingungen werden nach einem festen Schema ausgewertet: * **`dependencyGroups` sind ODER-verknüpft**: Es genügt, wenn **eine** der Gruppen vollständig erfüllt ist. * **`dependencies` innerhalb einer Gruppe sind UND-verknüpft**: Innerhalb einer Gruppe müssen **alle** Bedingungen erfüllt sein. * Ob eine einzelne Bedingung als erfüllt gilt, steuert zusätzlich `basketBehavior`: Bei `matchOnce` muss mindestens eine Warenkorb-Position die Bedingung erfüllen, bei `matchAll` alle Positionen, bei denen das geprüfte Feld einen Wert liefert. Im Beispiel oben gilt die Abhängigkeit also als erfüllt, wenn entweder die erste Gruppe zutrifft (eine Position mit der Farbe `camel` **und** eine Position mit leerem Freifeld `engraving` im Warenkorb) **oder** die zweite Gruppe (eine Position mit Größe `S`, `M` oder `L`). ### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------ | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | Eindeutige Kennung der Produktabhängigkeit, die selbst gewählt werden kann.
    Die `id` wird in den Validierungen `shippingMethodValidation.productDependency` (Versandarten) und `paymentValidation.productDependency` (Zahlungsarten) angegeben.
    Mehr dazu unter: [Validierungs- und Prüfservices](/konfiguration/validierungs-und-prufservices#4-shippingmethodvalidation-versandarten-validierung) | | `disabledText` | string | Hinweis-/Fehlermeldung, die angezeigt wird, wenn Bedingungen nicht erfüllt sind.
    Bei Versandarten wird der Text im Frontend über [`$wsCheckout.getShippingMethodDisabledErrors()`](/frontend/referenz/module/wscheckout#wscheckout-getshippingmethoddisablederrors) ausgegeben. | | `dependencyGroups` | list (object) | Enthält eine oder mehrere Regelgruppen. Die Gruppen sind ODER-verknüpft (siehe Auswertungslogik oben). | | `dependencies` | list (object) | Liste einzelner Bedingungen innerhalb einer Gruppe. Die Bedingungen sind UND-verknüpft.
    Jede Bedingung legt fest, welches Feld geprüft wird, wie geprüft wird und welcher Vergleichswert ggf. nötig ist. | | `target` | oneOf | Definiert, welches Feld geprüft wird. (**Pflichtfeld**) | | `field` | singleAssoc | Referenz auf ein Produktfeld, das geprüft wird.
    Target: `content.productField, content.customProductField` | | `freeField` | string | Name eines freien Feldes (z.B. Freifeld am Produkt/Warenkorb), das geprüft wird. (Alternativ zu `field`) | | `type` | enum | **Pflichtfeld** Vergleichsart der Bedingung.
    Die möglichen Werte sind in der Tabelle „Prüfarten" unten beschrieben. | | `input` | oneOf | Vergleichswert der Bedingung. (nur erforderlich, wenn der `type` einen Vergleichswert benötigt).
    Z.b. nicht erforderlich bei `filled` / `empty.` | | `text` | object | Textbasierter Vergleichswert. | | `value` | string | Wert für textbasierte Vergleiche. (z. B. bei `value`, `prefix`, `matchsimplewildcard`) | | `list` | object | Werteliste für Listenvergleiche (z. B. bei `inlist`, `includedinlist`). | | `value` | list (string) | Werteliste für den Vergleich. | | `basketBehavior` | enum | Legt fest, wie viele Warenkorb-Positionen die Bedingung erfüllen müssen:
    `matchOnce` = mind. eine Position
    `matchAll` = alle Positionen, bei denen das geprüfte Feld einen Wert liefert.
    **Default:**`matchOnce` | ### Prüfarten (`type`) | **Wert** | **Beschreibung** | | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `filled` | Das Feld ist gefüllt. Kein `input` erforderlich. | | `empty` | Das Feld ist leer. Kein `input` erforderlich. | | `value` | Der Wert des Feldes entspricht dem in `input` angegebenen Wert. | | `notvalue` | Der Wert des Feldes entspricht nicht dem in `input` angegebenen Wert. | | `inlist` | Der Wert des Feldes ist in der in `input` angegebenen Liste enthalten. | | `notinlist` | Der Wert des Feldes ist nicht in der in `input` angegebenen Liste enthalten. | | `prefix` | Der Wert des Feldes beginnt mit dem in `input` angegebenen Präfix. | | `notprefix` | Der Wert des Feldes beginnt nicht mit dem in `input` angegebenen Präfix. | | `greater` | Der Wert des Feldes ist (numerisch) größer als der in `input` angegebene Wert. | | `smaller` | Der Wert des Feldes ist (numerisch) kleiner als der in `input` angegebene Wert. | | `includedinlist` | Der in `input` angegebene Wert ist in der Werte-Liste des Produktdatenfeldes enthalten (für Felder, die mehrere Werte enthalten). | | `notincludedinlist` | Der in `input` angegebene Wert ist nicht in der Werte-Liste des Produktdatenfeldes enthalten. | | `matchsimplewildcard` | Der Wert des Feldes stimmt mit dem in `input` angegebenen Muster überein. Als Platzhalter stehen `?` (genau ein beliebiges Zeichen) und `*` (beliebig viele beliebige Zeichen) zur Verfügung; beide können mehrfach und an beliebiger Position verwendet werden. | | `notmatchsimplewildcard` | Der Wert des Feldes stimmt nicht mit dem in `input` angegebenen Muster überein. | ## `checkout.shippingMethod` - Versandarten Definiert verfügbare Versandarten und deren Verhalten im Checkout. Neben Aktivierung, Name und Bestellhinweisen lassen sich **Preisstaffeln nach Gewicht** (`weightCost`) und **nach Warenkorb-Zwischensumme** (`basicCost`) konfigurieren. Über **Validierungen** (`validations`) können Bedingungen wie **zulässige Länder**, **nur physische Produkte** oder weitere Regeln hinterlegt werden. Ergänzend sind **Beschreibung**, **Bild/Icon** und **externer Link** (z. B. Carrier-Info) möglich. Über das Feld `group` lässt sich eine Versandart zudem einer [Versandarten-Gruppe](#checkout-shippingmethodgroup-versandarten-gruppen) zuordnen. So entstehen klar benannte, regelkonforme Versandoptionen mit transparenter Preislogik und optionalen Einschränkungen. Nachfolgend eine Beispielkonfiguration für `checkout.shippingMethod`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "id": "checkout.shippingMethod.dhl_standard", "name": "DHL Standard", "orderText": "Versand mit DHL, Lieferzeit 2–3 Werktage.", "weightCost": [ { "weight": 0.0, "cost": 4.90 }, { "weight": 5.0, "cost": 6.90 }, { "weight": 31.5, "cost": 12.90 } ], "basicCost": [ { "subtotal": 0.0, "cost": 4.90 }, { "subtotal": 50.0, "cost": 0.0 } ], "validations": [ { "service": "shippingMethodValidation.shippingCountry", "options": { "countries": ["DE", "AT"] } }, { "service": "shippingMethodValidation.onlyPhysicalProducts", "options": { "enabled": true } } ], "link": "https://www.dhl.de/de/privatkunden/pakete-versenden.html", "description": "Zuverlässiger Standardversand innerhalb DE/AT.", "image": "https://cdn.example.com/shipping/dhl.png", "type": "standard", "group": "checkout.shippingMethodGroup.standard" } ``` ### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | -------------------------------------------------------------------------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `active` | bool | Aktiviert / deaktiviert die Versandart im Shop. | | `id` | string | Eindeutige Kennung der Versandart. | | `name` | string | Anzeigename der Versandart. | | `orderText`
    (**zukünftiges Feature / befindet sich noch in Entwicklung**) | text | Bestell- / Hinweistexte zur Versandart. | | `validations` | multiService | Liste von Prüf- / Freigaberegeln (z.B. Länder - / Produktbeschränkungen). | | `link`
    (**zukünftiges Feature / befindet sich noch in Entwicklung**) | text | Externer Link mit Zusatzinfos. | | `description`
    (**zukünftiges Feature / befindet sich noch in Entwicklung**) | string | Kurze Beschreibung der Versandart. | | `image`
    (**zukünftiges Feature / befindet sich noch in Entwicklung**) | string | Bild- / Icon-URL der Versandart. | | `weightCost` | object | Staffelpreise nach Gewicht. | | `basicCost` | object | Staffelpreise nach Warenkorb-Zwischensumme. | | `taxable` | bool | Legt fest, ob auf die Versandkosten Steuern berechnet werden. Bei `false` wird der Versandkosten-Steuersatz in der Bestellung mit `0` ausgewiesen. | | `type` | enum | `standard` oder `pickup`.
    Bei `standard` handelt es sich um einen “normalen” Versand über einen Versender wie DHL, UPS etc. `pickup` kennzeichnet, dass es sich um “Click and Collect” und somit um eine Abholung in einem Store, Markt oder einer Filiale handelt.
    Für die Auswahl im Bestellablauf wird die Aktion `CheckoutStoreIdSelect` verwendet.
    Wurde kein Markt ausgewählt wird Standardmäßig der Markt aus der allgemeinen Auswahl verwendet. | | `group` | singleAssoc | Ordnet die Versandart einer Versandarten-Gruppe zu.
    Target: `checkout.shippingMethodGroup` | ## `checkout.shippingMethodGroup` - Versandarten-Gruppen Definiert Gruppen, zu denen Versandarten zusammengefasst werden können (z. B. nach Anbieter oder Lieferart). Eine Versandart wird über ihr Feld `group` einer Gruppe zugeordnet. Je Gruppe lassen sich Name, Beschreibung, Bild und ein Link hinterlegen - etwa, um im Frontend mehrere Versandarten gebündelt und einheitlich darzustellen. Nachfolgend eine Beispielkonfiguration für `checkout.shippingMethodGroup`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "checkout.shippingMethodGroup.express", "name": "Express-Versand", "description": "Schnelle Lieferung innerhalb von 24 Stunden.", "image": "https://cdn.example.com/shipping/express.png", "link": "https://www.example.com/versand/express" } ``` ### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------- | | `id` | string | Eindeutige Kennung der Versandarten-Gruppe. | | `name` | text | Anzeigename der Gruppe. | | `description` | text | Beschreibung der Gruppe. | | `image` | string | Bild- / Icon-URL der Gruppe. | | `link` | string | Externer Link mit Zusatzinfos zur Gruppe. | Im Template werden die Gruppen über `$wsConfig.shippingMethodGroups` gelesen. Die einer Versandart zugewiesene Gruppe steht dort im Feld `group` der Versandart. ## `checkout.shipTrack` - Paketverfolgung Konfiguriert die Anbindung an Versanddienstleister zur **Sendungsverfolgung**. Hinterlegt werden Provider-Kennung und **Zugangsdaten** (API-User/Token) sowie ein **Sprachcode** für Provider-Antworten und Labeling. Auf Basis dieser Daten lassen sich **Tracking-Links** und Statusinformationen im Checkout bzw. im Kundenkonto bereitstellen und automatisiert in Benachrichtigungen verwenden. Nachfolgend eine Beispielkonfiguration für `checkout.shipTrack`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "shiptrack.dhl", "provider": "DHL", "username": "api-user-123", "password": "s3cr3t-token", "languageCode": "de" } ``` ### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | -------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | Eindeutige Kennung der Versand-Tracking-Konfiguration. | | `provider` | string | Anbieter-Kennung. Derzeit wird ausschließlich `DHL` unterstützt - der Wert muss exakt so geschrieben werden (Groß-/Kleinschreibung beachten), sonst kann die Tracking-Integration nicht zugeordnet werden. | | `username` | string | API-Benutzername / Zugang für den Provider. | | `password` | string | API-Passwort / Token für den Provider. | | `languageCode` | string | Sprachcode für Labels / Antworten des Providers (ISO, z.B. de, en).
    Leer = bei `DHL` wird `de` verwendet. | # content - Katalog (Kategorien & Produkte) Source: https://dokumentation.websale.de/konfiguration/content-katalog-kategorien-produkte Der Knoten `content` bildet die zentrale Konfigurationsebene für alle Inhalte des Katalogs.
    Hier werden die Strukturen, Felder und Einstellungen definiert, die zur Verwaltung von Produkten, Kategorien und den dazugehörigen Medien- und Attributsdaten dienen. Zu den wichtigsten Bereichen gehören: * **Kategorien**
    Definition von Kategoriefeldern, Feldgruppen und ergänzenden Informationen zur Darstellung im Frontend. * **Produkte**
    Verwaltung von Produktfeldern, Varianten, Produkttypen und allgemeinen Produkteinstellungen. * **Medien**
    Steuerung von Bild- und Videoformaten, Speicherzielen und automatischen Konvertierungsprozessen. * **Verknüpfungen & Erweiterungen**
    Zuordnung benutzerdefinierter Felder über `usedFields`, Definition zusätzlicher Attribute oder Feldgruppen. Die im Knoten `content` enthaltenen Konfigurationen bilden somit die Grundlage für sämtliche katalogbasierten Funktionen des Shops, von der Produktdarstellung im Frontend bis zur Datenintegration über die API. Die einzelnen Konfigurationsbereiche sind im Admin Interface unter verschiedenen Services zu finden, beispielsweise *Katalog → Produkte* oder *Katalog → Kategorien*. Sie können auch über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) bearbeitet werden. ## `content*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `content` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "content": { "categoryFieldGroup": {...}, "categoryField": {...}, "contentFieldDataTypes": {...}, "customCategoryField": {...}, "customProductField": {...}, "imageFormat": {...}, "inserts": {...}, "inventory": {...}, "productAttribute": {...}, "productFieldGroup": {...}, "productField": {...}, "productSettings": {...}, "productType": {...}, "usedFields": {...}, "videoSettings": {...} } } ``` #### Parameterbeschreibungen | **Parameter** | **Beschreibung** | | ----------------------- | ----------------------------------------------------------------------------------------------- | | `categoryFieldGroup` | Gruppiert Kategoriefelder. | | `categoryField` | Vordefinierte Standardfelder für Kategorien. | | `contentFieldDataTypes` | Zentrale Typendefinitionen für Felder. | | `customCategoryField` | Eigene (benutzerdefinierte) Kategoriefelder. | | `customProductField` | Eigene Produktfelder für individuelle Datenpunkte. | | `imageFormat` | Vorgaben für Bildformate / -größen. | | `inserts` | Einstellungen der Werbemittelkennzeichnung (Aktivierung, Trennzeichen, Position, Standardcode). | | `inventory` | Einstellungen zum Bestands- / Verfügbarkeitsmanagement. | | `productAttribute` | Verwaltung von Attributen zur Katalognavigation und Suche. | | `productFieldGroup` | Gruppiert Produktfelder. | | `productField` | Vordefinierte Standardfelder für Produkte. | | `productSettings` | Globale Produktschalter & Defaults. | | `productType` | Definition von Produkttypen. | | `usedFields` | Nutzungsübersicht der Felder. | | `videoSettings` | Vorgaben für Videoeinbindung. | ## `content.categoryField` - Standard-Kategoriefelder Dieser Knoten beschreibt die vordefinierten Systemfelder einer Kategorie. Erstellen oder Löschen zusätzlicher Felder ist an dieser Stelle nicht möglich. Je nach Feld sind bestimmte Eigenschaften editierbar, andere werden ausschließlich vom System geführt. Bestehende Werte können über das Admin Interface (Service „Katalog → Kategorien“) oder über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) geändert werden, sofern das jeweilige Feld editierbar ist. Systemverwaltete Felder wie beispielsweise Timestamps sind schreibgeschützt. #### Beispielkonfiguration `content.categoryField.descr` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "manualEditable": true, "name": "descr", "required": false, "searchable": false, "serviceFilter": false, "type": { "bool": null, "dateTime": null, "enumeration": null, "float": null, "image": null, "integer": null, "list": null, "map": null, "multiFormatImage": null, "price": null, "text": { "maxLength": 4096, "regex": null, "searchIndexBehaviour": "notAnalyzed" }, "uinteger": null, "video": null } } ``` In diesem Beispiel wurde das Feld `descr` als Kategorie-Beschreibungsfeld definiert, das redaktionell gepflegt werden kann. Es ist nicht suchrelevant und kein Pflichtfeld. #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `dataId` | `string` | Systeminterne eindeutige ID des Feldes.
    Wird automatisch vergeben und ist schreibgeschützt (`readonly`). | | `label` | `string` | Anzeigename des Feldes im Admin Interface.
    Dient der besseren Lesbarkeit und kann angepasst werden, ohne die Funktion des Feldes zu beeinflussen. | | `manualEditable` | `bool` | Steuert, ob der Wert dieses Feldes manuell bearbeitet werden darf.
    `true` = Das Feld kann über das Admin Interface, die REST API oder angebundene Systeme wie beispielsweise eine WaWi geändert werden.
    `false` = Das Feld ist schreibgeschützt und wird ausschließlich vom System gesetzt, beispielsweise Felder wie `timestampCreatedAt`, die automatisch vom Shop verwaltet werden. | | `name` | `string` | Technischer Name des Feldes. Muss eindeutig sein.
    Übersicht der Standardfelder für Kategorien:
    - `active` - Kategorie wird im Shop verwendet
    - `descr` - Beschreibung der Kategorie
    - `hidden` - Kategorie wird nicht in der Navigation angezeigt
    - `id` - Eindeutiger Index für die Kategorie
    - `name` - Name der Kategorie
    - `productAssignmentType` - Methode, wie der Kategorie Produkte zugewiesen werden, beispielsweise über den RuleBuilder oder direkte Zuweisung von Produktindexen
    - `productRules` - Regeln für die Produktzuweisung
    - `timestampCreatedAt` - Erstellungsdatum Kategorie (Unix-Timestamp)
    - `timestampUpdatedAt` - Letzte Aktualisierung der Kategorie (Unix-Timestamp) | | `required` | `bool` | Markiert das Feld als Pflichtfeld.
    `true` = Feld muss ausgefüllt werden.
    `false` = Feld ist optional. | | `searchable` | `bool` | Gibt an, ob der Inhalt des Feldes in der Suchindizierung der Core-Suche berücksichtigt wird.
    `true` = Feld wird in den Suchindex aufgenommen.
    `false` = Feld bleibt für die Suche unberücksichtigt.
    Diese Einstellung hat keine Auswirkung auf das Suchmodul WEBSALE \| search.
    Hier sind separate Anpassungen im Suchmodul selbst notwendig. | | `type` | `oneOf` | Datentyp des Feldes. Zulässige Werte sind über `contentFieldDataTypes` definiert.
    → [siehe Datentypen](/frontend/referenz/datentypen) | ## `content.categoryFieldGroup` - Kategoriefeldgruppen Der Knoten `content.categoryFieldGroup` dient zur logischen Gruppierung von Kategoriefeldern innerhalb des Katalogs. Da in umfangreichen Shops eine große Anzahl individueller Kategorie-Felder existieren kann, lassen sich diese hier in thematische Gruppen zusammenfassen, etwa für SEO-Daten, Bilder, Marketinginhalte oder Stammdaten. Die Gruppierung erleichtert die Übersichtlichkeit im Admin Interface und sorgt dafür, dass Felder strukturiert dargestellt werden. Eine Feldgruppe kann mehrere bestehende Felder referenzieren. Neue Gruppen können aktuell nur über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) erstellt werden. #### Beispielkonfiguration `content.categoryFieldGroup.robots` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "fields": [ "customCategoryField.robotsNoIndex", "customCategoryField.robotsNoFollow" ], "name": "Robots" } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | `string` | Anzeigename der Feldgruppe.
    Dient zur eindeutigen Identifikation und zur Anzeige im Admin Interface. | | `fields` | `multiAssoc` | Enthält eine Liste der zugehörigen Felder.
    Hier können Felder vom Typ `content.categoryField` oder `content.customCategoryField` referenziert werden. | ## `content.contentFieldDataTypes` - Datentypen (oneOf) Der Typ `contentFieldDataTypes` definiert, welcher Datentyp `type` einem Produkt- und/oder Kategoriedatenfeld zugewiesen wird. Dadurch stellt WEBSALE einheitliche, validierbare Felddefinitionen für Kategorien und Produkte zur Verfügung, beispielsweise „Text mit max. Länge“, „Ganzzahl mit Min/Max“ oder „Auswahlliste“. Es gilt das **oneOf-Prinzip**: Genau ein Datentyp ist aktiv, alle anderen Typobjekte sind nicht gesetzt, also `null` oder nicht vorhanden. #### Beispielkonfiguration für die Zuweisung von Datentypen `type` bei einem Datenfeld ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { ... "type": { "bool": null, "dateTime": null, "enumeration": null, "float": null, "image": null, "integer": null, "list": null, "map": null, "multiFormatImage": null, "price": null, "text": { "maxLength": 4096, "regex": null, "searchIndexBehaviour": "notAnalyzed" }, "uinteger": null, "video": null } ... } ``` #### Überblick der verfügbaren Datentypen `int?`, `uint?`, `float?`, `string?` bedeuten **optional**. Wird die Eigenschaft nicht gesetzt, gilt „keine zusätzliche Einschränkung“. | **Typname** | **Eigenschaft (Auszug)** | **Beschreibung** | | ------------------ | ----------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `bool` | - | Wahr/Falsch. In Beschreibungen stets die Wirkung für `true` / `false` benennen. | | `dateTime` | - | Zeitstempel/Datum-Uhrzeit (ISO-8601). Oft systemgeführt. | | `enumeration` | `options` (`list`) | Auswahlliste fester Werte (Whitelist). | | `float` | `min` (`float?`), `max` (`float?`) | Gleitkommazahl, beispielsweise für Maße und Gewichte. | | `image` | - | Einzelnes Bild (Format/Storage außerhalb festgelegt). | | `integer` | `min` (`int?`), `max` (`int?`) | Signierte Ganzzahl (inkl. negative Werte). | | `list` | `maxEntries` (`int`) | Geordnete Liste homogener Werte (Typ aus Feldkontext). | | `map` | `maxEntries` (`int`) | Schlüssel-Wert-Sammlung (Strings → Werte, Größe begrenzen). | | `multiFormatImage` | `imageFormats` (`multiAssoc → content.imageFormat`) | Bildreferenz in mehreren Zielformaten / Breakpoints. | | `price` | `min` (`float?`), `max` (`float?`) | Preise und Beträge. Ein Feld dieses Typs trägt zusätzlich zum Standardpreis geplante Aktionspreise mit einem Von-Bis-Zeitraum. Der Währungskontext wird separat konfiguriert. | | `text` | `searchIndexBehaviour` (`notAnalyzed` \| `analyzed`), `maxLength` (`int?`), `regex` (`string?`) | Freitextfeld. `searchIndexBehaviour` steuert, ob der Feldinhalt für Suchanfragen ausgewertet wird (`analyzed`/`notAnalyzed`). `maxLength` begrenzt optional die Zeichenanzahl, `regex` ermöglicht eine optionale Musterprüfung. | | `uinteger` | `min` (`uint?`), `max` (`uint?`) | **Unsignierte** Ganzzahl (≥ 0). | | `video` | - | Einzelnes Video (Referenz/Storage außerhalb). | ### Details & Parametertabellen je Typ ### `bool` #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "type": { "bool": {} } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | - | - | Keine zusätzlichen Eigenschaften.
    **Wirkung im Feldkontext klar dokumentieren:**
    `true` = Funktion/Eigenschaft ist **aktiv**, beispielsweise „sichtbar“ oder „verfügbar“.
    `false` = **inaktiv**. | ### `dateTime` #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "type": { "dateTime": {} } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | - | - | Keine zusätzlichen Eigenschaften.
    Erwartetes Format: ISO-8601, beispielsweise `2025-10-28T12:34:56Z`.
    Wird häufig systemgeführt, beispielsweise bei `timestampCreatedAt`. | ### `enumeration` #### Beispiel - Produktzuordnungstyp ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "type": { "enumeration": { "options": ["manual", "rules"] } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | -------------- | ---------------------------------------------------------------------------------------------- | | `options` | `list` | Liste der zulässigen Werte (Whitelist).
    Eingaben müssen einem der Einträge entsprechen. | ### `float` #### Beispiel: Gewicht in kg ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "type": { "float": { "min": 0.0, "max": 200.0 } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | -------- | ---------------------------- | | `min` | `float?` | Untere Schranke (inklusive). | | `max` | `float?` | Obere Schranke (inklusive). | ### `image` #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "type": { "image": {} } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------- | | - | - | Bildreferenz. Validierung, Größenbeschränkung und Speicherort werden außerhalb definiert, beispielsweise in `content.imageFormat`. | ### `integer` #### Beispiel: Bereich -100 bis 100 ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "type": { "integer": { "min": -100, "max": 100 } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ---------------------------- | | `min` | `int?` | Untere Schranke (inklusive). | | `max` | `int?` | Obere Schranke (inklusive). | ### `list` #### Beispiel: maximal 20 Einträge ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "type": { "list": { "maxEntries": 20 } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------------- | | `maxEntries` | `int` | Maximale Anzahl der Listeneinträge. | ### `map` #### Beispiel: Key-Value-Struktur für Eigenschaften ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "type": { "map": { "maxEntries": 50 } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------------------- | | `maxEntries` | `int` | Maximale Anzahl der Schlüssel-Wert-Paare. | ### `multiFormatImage` #### Beispiel: zwei Ausgabeformate ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "type": { "multiFormatImage": { "imageFormats": ["thumb_1x1", "hero_16x9"] } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | -------------- | ---------------------------------- | -------------------------------------------------------------------------- | | `imageFormats` | `multiAssoc → content.imageFormat` | Verknüpfung zu mehreren definierten Bildformaten (Breakpoints, Varianten). | ### `price` #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "type": { "price": { "min": 0.0, "max": 999999.99 } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | -------- | ---------------------------- | | `min` | `float?` | Untere Schranke (inklusive). | | `max` | `float?` | Obere Schranke (inklusive). | **Hinweis:** Währung, Steuerkontext und Rundungslogik werden **außerhalb** dieses Typs konfiguriert. Siehe → [general - Allgemeine Shopeinstellungen](/konfiguration/general-allgemeine-shopeinstellungen) Ein Feld vom Typ `price` trägt neben dem Standardpreis geplante Aktionspreise mit einem Von-Bis-Zeitraum. Im Template liefert das Feld immer den zum Aufrufzeitpunkt gültigen Preis, den Standardpreis liefert `rawPrice`. Wie diese Preise gepflegt und ausgeliefert werden, beschreiben die Abschnitte [Preis eines Produkts](/frontend/referenz/module/wsproducts#preis-eines-produkts) und [Zeitgesteuerte Preise (Aktionspreise)](/schnittstellen/admin-interface-api/api-referenz-produkte#zeitgesteuerte-preise-aktionspreise). Im Suchindex wird ausschließlich der Standardpreis abgelegt. ### `text` #### Beispiel: SEO-Text mit Volltextsuche ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "type": { "text": { "searchIndexBehaviour": "analyzed", "maxLength": 512, "regex": null } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `searchIndexBehaviour` | `enum`
    (`notAnalyzed`, `analyzed`) | Steuert, ob und in welcher Form der Inhalt des Feldes im Suchindex ausgewertet wird.
    Alle Inhalte des Feldes werden an Elasticsearch übertragen. Über `searchIndexBehaviour` wird lediglich festgelegt, ob das Feld bei Suchanfragen berücksichtigt wird, beispielsweise bei Volltextsuche oder Filtern, oder ob es nur als Datenspeicher dient.
    - `analyzed` = Volltext (tokenisiert, linguistisch analysiert)
    - `notAnalyzed` = exakte Indexierung ohne Aufsplittung.
    Diese Einstellung greift nicht für das Suchmodul WEBSALE \| search.
    Das technische Mapping des Feldes in Elasticsearch wird durch diese Einstellung nicht verändert. | | `maxLength` | `int?` | Maximale Zeichenzahl. Ohne Wert: keine Begrenzung. | | `regex` | `string?` | Optionaler regulärer Ausdruck zur Eingabevalidierung. | ### `uinteger` #### Beispiel: nur nichtnegative Werte ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "type": { "uinteger": { "min": 0, "max": 10000 } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------- | | `min` | `uint?` | Untere Schranke (≥ 0, inklusive). | | `max` | `uint?` | Obere Schranke (inklusive). | ### `video` #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "type": { "video": {} } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------ | | - | - | Videoreferenz. Format, Codec und Speicherort werden außerhalb definiert. | ## `content.customCategoryField` - Benutzerdefinierte Kategoriefelder Über den Knoten `content.customCategoryField` werden zusätzliche, frei definierbare Felder angelegt, die zur Beschreibung von Kategorien im Katalog genutzt werden können. Damit lassen sich individuelle Informationen an Kategorien hinterlegen, etwa Texte, Bilder, SEO-Metadaten oder technische Eigenschaften. Diese können im Frontend oder in externen Systemen angezeigt oder weiterverarbeitet werden, beispielsweise in Warenwirtschaft, Suchindex oder PIM. Diese Felder ergänzen die festen Standardfelder aus `content.categoryField` und ermöglichen eine flexible Erweiterung der Kategoriestruktur. Neue Felder können entweder über das Admin Interface im Service „Katalog → Kategorien“ angelegt oder über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) erstellt werden. #### Beispielkonfiguration `content.customCategoryField.image` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Kategorie", "manualEditable": true, "name": "image", "required": false, "searchable": false, "serviceFilter": false, "type": { "bool": null, "dateTime": null, "enumeration": null, "float": null, "image": null, "integer": null, "list": null, "map": null, "multiFormatImage": { "imageFormats": [ "content.imageFormat.category", "content.imageFormat.categoryWebp" ] }, "price": null, "text": null, "uinteger": null, "video": null } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `dataId` | `string` | Systeminterne eindeutige ID des Feldes. Wird automatisch generiert und ist **read-only**. | | `label` | `string` | Anzeigename des Feldes im Admin Interface. Dient der besseren Lesbarkeit und kann frei vergeben werden. | | `manualEditable` | `bool` | Gibt an, ob der Feldwert manuell geändert werden darf.
    `true` = Feld kann über das Admin Interface, die REST API oder WaWi gepflegt werden.
    `false` = Feld ist **schreibgeschützt**, beispielsweise bei Systemfeldern.
    *Typische Verwendung:* Schreibgeschützte Felder wie automatisch berechnete Werte oder systemseitig gesetzte Status. | | `name` | `string` | Technischer Name des Feldes. Muss eindeutig sein. Frei wählbar für eigene Felder, beispielsweise `image`, `seoText` oder `bannerVideo`. | | `required` | `bool` | Markiert das Feld als Pflichtfeld.
    `true` = Feld muss befüllt werden, sonst keine Speicherung möglich.
    `false` = Feld ist optional. | | `searchable` | `bool` | Steuert, ob der Feldinhalt in die Suchindizierung aufgenommen wird.
    `true` = Feld wird in den Suchindex integriert.
    `false` = Feld bleibt für die Suche unberücksichtigt.
    Diese Einstellung greift nicht für das Suchmodul WEBSALE \| search. | | `type` | `oneOf` | Datentyp des Feldes.
    Die verfügbaren Typen sind in `contentFieldDataTypes` definiert, beispielsweise `text`, `image`, `multiFormatImage`, `enumeration` oder `price`.
    → [siehe Datentypen](/frontend/referenz/datentypen) | Auch Kategoriefelder vom Typ `price` können geplante Aktionspreise tragen. Aufbau und Wirkung sind im Abschnitt [Zeitgesteuerte Preise (Aktionspreise)](/schnittstellen/admin-interface-api/api-referenz-produkte#zeitgesteuerte-preise-aktionspreise) beschrieben. ## `content.customProductField` - Benutzerdefinierte Produktfelder Über den Knoten `content.customProductField` werden zusätzliche, frei definierbare Felder für Produkte angelegt. Diese Felder ermöglichen es, individuelle Produktinformationen zu erfassen, die über die Standardfelder hinausgehen, etwa Materialien, technische Eigenschaften, zusätzliche Texte, Medieninhalte oder Marketingattribute. So können produktrelevante Zusatzdaten gepflegt werden, die im Frontend, im Suchindex oder in externen Systemen verwendet werden, beispielsweise in PIM, ERP oder WaWi. Neue Felder können entweder über das Admin Interface im Service „Katalog → Produkte“ angelegt oder über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) erstellt werden. #### Beispielkonfiguration `content.customProductField.material` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Material", "manualEditable": true, "name": "material", "protectedField": false, "required": false, "searchBoost": 1, "searchable": false, "serviceFilter": false, "type": { "bool": null, "dateTime": null, "enumeration": null, "float": null, "image": null, "integer": null, "list": null, "map": null, "multiFormatImage": null, "price": null, "text": { "maxLength": 100, "regex": null, "searchIndexBehaviour": "notAnalyzed" }, "uinteger": null, "video": null }, "variant": false } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `dataId` | `string` | Systeminterne eindeutige ID des Feldes. Wird automatisch generiert und ist **read-only**. | | `label` | `string` | Anzeigename des Feldes im Admin Interface. Dient der besseren Lesbarkeit und kann frei vergeben werden. | | `manualEditable` | `bool` | Gibt an, ob das Feld manuell bearbeitet werden darf.
    - `true` = Feld kann über das Admin Interface, die REST API oder WaWi gepflegt werden.
    - `false` = Feld ist **schreibgeschützt**, beispielsweise bei Systemfeldern oder automatisch gesetzten Werten. | | `name` | `string` | Technischer Name des Feldes. Muss eindeutig sein. Wird beispielsweise in Templates oder API-Abfragen referenziert. | | `protectedField` | `bool` | Steuert, ob das Feld vor ungewollten Änderungen geschützt ist.
    - `true` = Feld kann **nicht gelöscht oder überschrieben** werden.
    - `false` = Feld kann jederzeit angepasst oder gelöscht werden.
    *Typische Verwendung:* Schutz von systemkritischen Feldern. | | `required` | `bool` | Markiert das Feld als Pflichtfeld.
    - `true` = Feld muss befüllt werden.
    - `false` = Feld ist optional. | | `searchable` | `bool` | Steuert, ob der Feldinhalt in den Suchindex aufgenommen wird.
    - `true` = Feld wird bei der Suche berücksichtigt.
    - `false` = Feld wird nicht indexiert.
    Diese Einstellung greift nicht für das Suchmodul WEBSALE \| search. | | `searchBoost` | `int` | Gewichtungsfaktor für die Suche.
    Höhere Werte verstärken den Einfluss des Feldes auf das Suchranking.
    Standardwert: `1`.
    Diese Einstellung greift nicht für das Suchmodul WEBSALE \| search. | | `serviceFilter` | `bool` | Kennzeichnet, ob das Feld in servicebasierten Filtern verwendet werden kann, beispielsweise in API-Abfragen oder dynamischen Produktauswahlen.
    - `true` = Feld kann als Filterkriterium genutzt werden.
    - `false` = Feld steht für Filter nicht zur Verfügung. | | `type` | `oneOf` | Datentyp des Feldes.
    Die verfügbaren Typen sind in `contentFieldDataTypes` → [siehe Datentypen](/frontend/referenz/datentypen) | | `variant` | `bool` | Gibt an, ob das Feld als **variantenrelevantes Attribut** gilt.
    - `true` = Feld kann bei Produktvarianten unterschiedliche Werte haben, beispielsweise Farbe oder Größe.
    - `false` = Feld gilt für alle Varianten gleich. | Felder vom Typ `price` können geplante Aktionspreise mit einem Von-Bis-Zeitraum tragen. Wie diese Preise über die Schnittstelle gepflegt und ausgeliefert werden, beschreibt der Abschnitt [Zeitgesteuerte Preise (Aktionspreise)](/schnittstellen/admin-interface-api/api-referenz-produkte#zeitgesteuerte-preise-aktionspreise). Im Suchindex wird ausschließlich der Standardpreis abgelegt. ## `content.imageFormat` - Bildformate & Konvertierungseinstellungen Über den Knoten `content.imageFormat` werden Bildformate und zugehörige Konvertierungsregeln definiert, die vom System beim Import, bei der automatischen Umwandlung oder bei der Ausgabe von Produkt-, Kategorie- oder CMS-Bildern verwendet werden. Ein Bildformat beschreibt, wie ein Bild verarbeitet, geprüft, gespeichert und benannt wird.
    Dazu gehören Einstellungen für Skalierung, Zuschnitt, Dateigröße, DPI-Grenzen, Ausgabeordner und Kompressionsqualität. Neue Bildformate können entweder über das Admin Interface im Service „Templates und Content → Bildkonverter“ angelegt oder über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) erstellt werden. #### Beispielkonfiguration `content.imageFormat.normal` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "autoConvert": { "active": false, "allowExternalTrigger": false, "hour": null, "sourceDirectory": "products", "weekday": null }, "check": { "dpi": { "active": false, "max": 0, "min": 0 }, "fileSize": { "active": false, "max": 0, "maxUnit": "byte", "min": 0, "minUnit": "byte" }, "inputTypeRestriction": { "active": false, "allowedTypes": null } }, "convert": { "additionalArguments": "", "changeType": { "active": false, "type": "jpg" }, "quality": { "active": true, "value": 75 }, "removeMetadata": true, "resize": { "active": true, "background": "#FFFFFF", "height": 660, "orientation": "center", "type": "scale", "width": 600 }, "sharpen": { "active": false, "sigma": 1 } }, "description": "normal - bild", "name": "Normal Produkt", "output": { "handleIfExists": "overwrite", "nameSuffix": "", "targetDirectory": "products/normal" }, "type": "product" } ``` Dieses Beispiel definiert ein Standard-Bildformat für Produktbilder mit 600 × 660 px, Weiß als Hintergrund, JPG-Ausgabequalität 75 %, und automatischem Speichern unter `products/normal`. #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `autoConvert` | `object` | Zeit- oder triggerbasierte automatische Konvertierung. | | `active` | `bool` | Aktiviert automatische Umwandlung.
    - `true` = Regelmäßige Ausführung gemäß Zeitplan.
    - `false` = Nur manuell ausgelöst. | | `hour` | `list` | Stundenangaben (0 bis 23) für geplante Ausführung. | | `sourceDirectory` | `string` | Quellordner der zu konvertierenden Bilder. | | `weekday` | `list` | Liste der Wochentage (0 bis 6 = Sonntag bis Samstag), an denen konvertiert wird. | | `check` | `object` | Regeln zur Eingabeprüfung (Dateityp, Auflösung, Größe). | | `inputTypeRestriction` | | | | `active` | `bool` | Aktiviert die Typprüfung.
    - `true` = Nur definierte Dateitypen sind erlaubt.
    - `false` = Keine Einschränkung. | | `allowedTypes` | `list` | Liste zulässiger Dateitypen, beispielsweise `["jpg", "png", "webp"]`. | | `dpi` | | DPI-Prüfung | | `active` | `bool` | Aktiviert die DPI-Prüfung.
    - `true` = Dateien müssen innerhalb des DPI-Bereichs liegen.
    - `false` = Keine Prüfung. | | `min` | `unit` | Mindest-DPI. | | `max` | `unit` | Maximal-DPI. | | `fileSize` | | Größenprüfung | | `active` | `bool` | Aktiviert die Größenprüfung.
    - `true` = Prüft Dateigröße
    - `false` = Keine Prüfung | | `min` | `float` | Untere Grenze für Dateigröße. | | `max` | `float` | Obere Grenze für Dateigröße. | | `minUnit` | `enum` | Einheit: `byte`, `kiloByte`, `megaByte`. | | `maxUnit` | `enum` | Einheit: `byte`, `kiloByte`, `megaByte`. | | `convert` | `object` | Definition der Bildkonvertierung (Format, Qualität, Skalierung etc.). | | `changeType` | | Dateityp-Konvertierung | | `active` | `bool` | Aktiviert die Dateityp-Konvertierung.
    - `true` = Zieldatei wird in den angegebenen Typ umgewandelt
    - `false` = Originalformat bleibt erhalten | | `type` | `enum` | Ziel-Dateiformat: `jpg`, `jpeg`, `png`, `gif`, `webp`, `avif`. Standard: `jpg`. | | `quality` | | Qualitätssteuerung | | `active` | `bool` | Aktiviert die Qualitätssteuerung. - `true` = aktiviert - `false` = deaktiviert | | `value` | `uint` | Qualitätswert 0 bis 100 (100 = beste Qualität, größte Datei). | | `resize` | | Größenänderung | | `active` | `bool` | Aktiviert Größenänderung. - `true` = aktiviert - `false` = deaktiviert | | `type` | `enum` | Methode: `scale` (Proportional), `crop` (Zuschnitt), `stretch` (Streckung). | | `width` | `uint` | Zielbreite in px. | | `height` | `uint` | Zielhöhe in px. | | `background` | `string` | Hintergrundfarbe im Hex-Format, beispielsweise `#FFFFFF`. | | `orientation` | `enum` | Positionierung beim Zuschneiden/Platzieren:
    `center`, `north`, `south`, `east`, `west`, `northEast`, `southEast`, `northWest`, `southWest`. | | `sharpen` | | Schärfefilter | | `active` | `bool` | Aktiviert Schärfung.
    - `true` = Schärfefilter wird angewendet.
    - `false` = Keine Schärfung. | | `sigma` | `float` | Stärke des Schärfefilters (Standard 1.0). | | `removeMetadata` | `bool` | Entfernt Metadaten (EXIF und andere).
    - `true` = Metadaten werden gelöscht.
    - `false` = Metadaten bleiben erhalten. | | `additionalArguments` | `string` | Erweiterte Kommando- oder Toolparameter (für interne Konverter). | | `description` | `string` | Beschreibung oder Zweck des Formats (frei wählbar). | | `name` | `string` | Eindeutiger Name des Bildformats. Wird intern und im Admin Interface angezeigt. | | `output` | `object` | Zielpfad und Schreibregeln für die erzeugten Dateien. Details siehe Abschnitt *output*. | | `targetDirectory` | `string` | Zielverzeichnis für konvertierte Bilder (relativ zum Medien-Root). | | `nameSuffix` | `string` | Optionaler Namenszusatz, beispielsweise `_thumb` oder `_webp`. | | `handleIfExists` | `enum` | Verhalten bei existierender Datei:
    - `overwrite` = überschreiben
    - `skip` = überspringen
    - `counter` = neuen Namen mit Zähler erzeugen. | | `type` | `enum` | Klassifizierung des Formats. Zulässige Werte:
    - `product` = Produktbilder
    - `category` = Kategoriebilder
    - `cms` = CMS- oder Content-Bilder
    - `app` = App-Assets
    - `other` = Sonstige Bilder
    Standardwert: `product`. | ## `content.inserts` - Werbemittelkennzeichen Der Knoten `content.inserts` steuert die [Werbemittelkennzeichnung](/frontend/funktionsubersicht/werbemittelkennzeichnung) des Shops. Werbemittelkennzeichen (auch Werbemittelcodes genannt) ordnen Bestellpositionen einem Werbemittel wie beispielsweise einem Katalog, einer Anzeige oder einem Mailing zu und werden an die Produktnummer angehängt (beispielsweise `123456-09`). Es handelt sich um einen Singleton-Knoten, der die gesamte Funktion global schaltet und ihr Anzeigeverhalten festlegt. Welche Codes für ein einzelnes Produkt gültig sind, wird nicht hier, sondern über das Produktfeld `validInsertCodes` gepflegt (siehe [content.usedFields](#content-usedfields-zuordnung-benutzerdefinierter-felder)). Die Einstellungen können über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) erstellt und bearbeitet werden. #### Beispielkonfiguration `content.inserts` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "enabled": true, "defaultInsertCode": "", "separator": "-", "position": "after" } ``` In diesem Beispiel ist die Werbemittelkennzeichnung aktiv. Der Code wird mit einem Bindestrich hinter die Produktnummer gesetzt (beispielsweise `123456-09`). Ein Standardcode ist nicht hinterlegt, sodass Positionen ohne gültigen Code kein Kennzeichen erhalten. #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `enabled` | `bool` | Schaltet die gesamte Werbemittelkennzeichnung ein oder aus.
    - `true` = Codes werden erfasst, aufgelöst, gespeichert und im Shop angezeigt.
    - `false` = Die Funktion ist im gesamten Shop wirkungslos, unabhängig von den an den Produkten gepflegten Codes.
    Standardwert: `false`. | | `defaultInsertCode` | `string` | Code, der verwendet wird, wenn kein oder ein ungültiger Code erfasst wurde.
    Leer lassen, wenn in diesem Fall gar kein Kennzeichen gesetzt werden soll.
    Greift produktübergreifend für jede nicht auflösbare Eingabe. | | `separator` | `string` | Trennzeichen zwischen Produktnummer und Code (beispielsweise `-`).
    Standardwert: `-`. | | `position` | `enum` | Position des Codes relativ zur Produktnummer.
    - `after` = hinter der Produktnummer (`123456-09`)
    - `before` = vor der Produktnummer (`09-123456`)
    Standardwert: `after`. | ## `content.inventory` - Lagerverwaltung & Bestandsmeldungen Der Knoten `content.inventory` steuert die Lagerbestandsverwaltung des Shops sowie die Kommunikation bei geringen oder ausverkauften Beständen. Er definiert, ab welchen Grenzwerten Produkte als *verfügbar*, *niedrig* oder *nicht lieferbar* gelten, und welche Texte oder E-Mail-Benachrichtigungen in diesen Fällen verwendet werden. Darüber hinaus können automatische E-Mails an Verantwortliche oder Kundinnen und Kunden konfiguriert werden, beispielsweise bei niedrigen Lagerbeständen oder wenn ein Artikel wieder verfügbar ist. Neue Grenzen und Bestandsmeldungen können über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) erstellt werden. Die Statustexte `textGreen`, `textYellow`, `textRed` und `textRedOrder` sowie die zugehörigen Grenzwerte gelten als **globale Voreinstellung** für alle Produkte. Im Admin Interface kann pro Produkt im Abschnitt *Lagerbestand* zwischen `nach globalen Einstellungen` und `individuelle Einstellungen` gewählt werden. Bei `individuelle Einstellungen` überschreibt der am Produkt gepflegte Liefertext den globalen Wert. Der über `$wsInventory.load().deliveryText` ausgegebene Text entspricht dem für das jeweilige Produkt aktiven Wert. #### Beispielkonfiguration `content.inventory` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "backInStock": { "allow": true, "minStockForMail": 15, "mailSubject": "Produkt wieder verfügbar", "senderAddress": "noreply@websale.de", "senderName": "Mustershop", "template": "backInStock.htm" }, "greenYellowBorder": 50, "message": { "active": true, "fromAddress": "lagerbestand@websale.de", "fromName": "Lagerbestandswächter", "limit": 5, "mail": "dev-test@websale.de", "subject": "Lagerbestandsmitteilung", "template": "inventory.htm" }, "reservationTime": 10, "reservationTimeCheckout": 30, "reserveRedOrdable": true, "splitDeliveryText": true, "textGreen": "Auf Lager", "textRed": "Ausverkauft", "textRedOrder": "Wird nachbestellt", "textYellow": "Nur noch wenige Stück auf Lager", "yellowRedBorder": 0 } ``` In diesem Beispiel ist die Lagerbestandsüberwachung aktiv. Sobald der Bestand unter **50 Stück** fällt, wird die gelbe Warnstufe angezeigt, und ab **0 Stück** gilt der Artikel als ausverkauft. Zudem werden automatische Benachrichtigungen an den Lagerverantwortlichen und an Kundinnen und Kunden beim Wiedereintreffen aktiviert. #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `active` | `bool` | Aktiviert die Lagerbestandsverwaltung.
    - `true` = Lagerbestand wird überwacht und im Frontend angezeigt.
    - `false` = Keine Lagerprüfung, alle Artikel gelten als verfügbar. | | `backInStock` | `object` | Konfiguration der Benachrichtigung bei Wiederverfügbarkeit für Kundinnen und Kunden.
    Steuert, ob Kundinnen und Kunden automatisch informiert werden, sobald ein Produkt wieder verfügbar ist. | | `allow` | `bool` | Aktiviert die Funktion „Benachrichtigen, wenn wieder verfügbar“. - `true` = Kundinnen und Kunden können sich für eine E-Mail-Benachrichtigung anmelden. - `false` = Keine Benachrichtigung möglich. | | `minStockForMail` | `uint` | Mindestbestand, der erreicht werden muss, bevor eine "Wieder verfügbar"-E-Mail versendet wird.
    Gilt global für alle Produkte.
    Maßgeblich ist der absolute Bestand, nicht ein Statuswechsel (siehe Hinweis unten). | | `mailSubject` | `string` | Betreff der E-Mail, beispielsweise „Produkt wieder verfügbar“. | | `senderAddress` | `string` | Absenderadresse, beispielsweise `noreply@shop.de`. | | `senderName` | `string` | Absendername, beispielsweise der Shopname. | | `template` | `string` | E-Mail-Template für die Nachricht, beispielsweise `backInStock.htm`. | | `greenYellowBorder` | `uint` | Grenzwert (Menge), ab dem die Anzeige von **grün** auf **gelb** wechselt. Beispiel: `50`. | | `message` | `object` | Konfiguration automatischer internen Lagerbestandsmeldungen (an Händler/Admin). | | `active` | `bool` | Aktiviert die interne Benachrichtigung.
    - `true` = Warnmails werden versendet.
    - `false` = Keine Benachrichtigung möglich. | | `fromAddress` | `string` | Absenderadresse für Warnmails. | | `fromName` | `string` | Absendername, beispielsweise „Lagerbestandswächter“. | | `limit` | `uint` | Schwellwert für Bestandsmeldung.
    Wenn der Bestand ≤ Wert ist, wird eine Warnmail versendet. | | `mail` | `string` | Empfängeradresse für Warnmails. | | `template` | `string` | E-Mail-Template für die Benachrichtigung, beispielsweise `inventory.htm`. | | `subject` | `string` | Betreffzeile der E-Mail. | | `reserveRedOrdable` | `bool` | Steuert, ob auch ausverkaufte, aber nachbestellbare Artikel reserviert werden dürfen.
    - `true` = Reservierung erlaubt.
    - `false` = Reservierung nur für verfügbare Produkte. | | `reservationTime` | `uint` | Zeitspanne (in Minuten), für die ein Produkt bei Hinzufügen in den Warenkorb **reserviert** wird.
    Standard: `15` | | `reservationTimeCheckout` | `uint` | Zeitspanne (in Minuten), für die Produkte während des **Bestellvorgangs** reserviert bleiben.
    Standard: `30` | | `splitDeliveryText` | `bool` | Aktiviert getrennte Textanzeigen für Teillieferungen.
    - `true` = Getrennte Texte für verfügbare und nachgelieferte Produkte.
    - `false` = Einheitliche Anzeige. | | `textGreen` | `string` | Text für die grüne Statusanzeige, beispielsweise „Auf Lager“.

    | | `textRed` | `string` | Text für die rote Statusanzeige, beispielsweise „Ausverkauft“.

    | | `textRedOrder` | `string` | Text, wenn ein Artikel zwar ausverkauft, aber **nachbestellbar** ist, beispielsweise „Wird nachbestellt“.

    | | `textYellow` | `string` | Text für die gelbe Statusanzeige, beispielsweise „Nur noch wenige Stück auf Lager“.

    | | `yellowRedBorder` | `uint` | Grenzwert (Menge), ab dem ein Artikel als **rot** (nicht verfügbar) gilt.
    Beispiel: `0` | `minStockForMail` ist unabhängig von den Status-Grenzen (`greenYellowBorder` und `yellowRedBorder`). Die „Wieder verfügbar"-E-Mail wird ausgelöst, sobald der absolute Bestand den Wert `minStockForMail` erreicht, auch wenn sich der angezeigte Status (rot/gelb/grün) dabei nicht ändert. **Beispiel:** Ein Produkt hat die Grenzen Rot 0 bis 10, Gelb 10 bis 20 und Grün ab 20. `minStockForMail` ist `15`. * Steigt der Bestand von 0 auf 11, wechselt der Status von Rot auf Gelb. Es wird noch keine E-Mail versendet, da der Mindestbestand 15 nicht erreicht ist. * Steigt der Bestand danach von 11 auf 15, ändert sich der Status nicht, die E-Mails werden aber versendet, weil der Mindestbestand jetzt erreicht ist. ## `content.productField` - Standard-Produktdatenfelder Über den Knoten `content.productField` werden die vordefinierten Standardfelder der Produktdaten beschrieben. Diese Felder bilden die feste technische Basis für alle Produkte und können nicht gelöscht oder neu angelegt werden. Sie definieren, welche Eigenschaften jedes Produkt im System besitzt, etwa Name, Preis, Beschreibung oder Steuerinformationen. Je nach Feld kann festgelegt werden, ob es manuell editierbar, suchrelevant oder variantenspezifisch ist. Neue, zusätzliche Felder können nicht über diesen Knoten erstellt werden. Hierfür steht der separate Knoten `content.customProductField` zur Verfügung. Bestehende Werte können über das Admin Interface (Service „Katalog → Produkte“) oder über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) geändert werden, sofern das jeweilige Feld editierbar ist. Systemverwaltete Felder wie beispielsweise Timestamps sind schreibgeschützt. #### Beispielkonfiguration `content.productField.name` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "manualEditable": true, "name": "name", "protectedField": false, "required": true, "searchBoost": 6, "searchable": true, "serviceFilter": true, "type": { "bool": null, "dateTime": null, "enumeration": null, "float": null, "image": null, "integer": null, "list": null, "map": null, "multiFormatImage": null, "price": null, "text": { "maxLength": 255, "regex": null, "searchIndexBehaviour": "analyzed" }, "uinteger": null, "video": null }, "variant": true } ``` Dieses Beispiel zeigt das Standardfeld `name`, das für alle Produkte vorhanden ist. Es ist suchrelevant, Pflichtfeld und variantenspezifisch. Die maximale Länge beträgt 255 Zeichen. Das Standardfeld `price` ist vom Typ `price` und trägt damit neben dem Standardpreis geplante Aktionspreise. Wie diese gepflegt und ausgeliefert werden, beschreibt der Abschnitt [Zeitgesteuerte Preise (Aktionspreise)](/schnittstellen/admin-interface-api/api-referenz-produkte#zeitgesteuerte-preise-aktionspreise). #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `dataId` | `string` | Systeminterne eindeutige ID des Feldes.
    Wird automatisch vergeben und ist **read-only**. | | `label` | `string` | Anzeigename des Feldes im Admin Interface.
    Kann frei angepasst werden und dient nur der Lesbarkeit. | | `manualEditable` | `bool` | Gibt an, ob der Wert manuell bearbeitet werden darf.
    - `true` = Feld kann über das Admin Interface, die REST API oder WaWi geändert werden.
    - `false` = Feld ist **schreibgeschützt** und wird ausschließlich vom System gepflegt, beispielsweise `timestampCreatedAt`. | | `name` | `string` | Technischer Name des Feldes. Muss eindeutig sein.
    Folgende Standardfelder stehen zur Verfügung:
    - `active`
    - `descr`
    - `id`
    - `itemNumber`
    - `name`
    - `price`
    - `taxRateId`
    - `timestampCreatedAt`
    - `timestampUpdatedAt`
    Diese Felder sind fest vorgegeben und **nicht veränderbar**.
    Für eigene Felder siehe `content.customProductField`. | | `protectedField` | `bool` | Steuert, ob das Feld gegen Änderungen oder Löschung geschützt ist.
    - `true` = Feld kann **nicht** entfernt oder überschrieben werden.
    - `false` = Feld kann (innerhalb der erlaubten Grenzen) angepasst werden. | | `required` | `bool` | Gibt an, ob das Feld verpflichtend befüllt werden muss.
    - `true` = Pflichtfeld, beispielsweise Produktname oder Artikelnummer.
    - `false` = Optionales Feld. | | `searchable` | `bool` | Bestimmt, ob der Feldinhalt in den Suchindex aufgenommen wird.
    - `true` = Feld wird in der Suche berücksichtigt.
    - `false` = Feld bleibt für die Suche unberücksichtigt. | | `searchBoost` | `int` | Gewichtungsfaktor für die Suche.
    Höhere Werte erhöhen die Relevanz des Feldes im Suchranking.
    Standard: `1` | | `serviceFilter` | `bool` | Steuert, ob das Feld als Filterkriterium in servicebasierten Abfragen genutzt werden kann.
    - `true` = Feld kann in Filtern und API-Requests verwendet werden.
    - `false` = Feld steht für Filter nicht zur Verfügung. | | `type` | `oneOf` | Datentyp des Feldes. Nur ein Typ darf aktiv sein.
    Die verfügbaren Typen sind in `contentFieldDataTypes` beschrieben.
    → [siehe Datentypen](/frontend/referenz/datentypen) | | `text` | | | | `maxLength` | `integer` | Maximale Anzahl an Zeichen, die im Textfeld erlaubt sind. | | `regex` | `string` | Optionaler regulärer Ausdruck zur Validierung.
    - `null` = keine Prüfung.
    - `""` = Eingabe muss Muster entsprechen. | | `searchIndexBehaviour` | `string` | Steuert, wie der Text in der Suche indiziert wird.
    - `"analyzed"` = Tokenisierung/Volltextsuche
    - `"notAnalyzed"` = exakte Übereinstimmung (Keyword). | | `variant` | `bool` | Legt fest, ob das Feld variantenabhängig ist.
    - `true` = Feldwert kann sich je Variante unterscheiden, beispielsweise Farbe, Größe oder Preis.
    - `false` = Feld gilt für alle Varianten eines Produkts gleich. | ## `content.productSettings` - Allgemeine Produkteinstellungen Der Knoten `content.productSettings` enthält allgemeine Einstellungen, die das Verhalten der Produktdarstellung und -kennzeichnung im Shop beeinflussen. Aktuell umfasst dieser Abschnitt insbesondere die Definition, wie lange ein Produkt als „neu“ markiert werden soll. Die Settings können über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) erstellt werden. #### Beispielkonfiguration `content.productSettings` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "daysNewTagged": 14 } ``` In diesem Beispiel werden Produkte für **14 Tage** nach ihrer Erstellung als *neu* gekennzeichnet.
    Nach Ablauf dieser Frist entfällt die Kennzeichnung automatisch. #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `daysNewTagged` | `int` | Gibt an, **wie viele Tage** nach der Erstellung ein Produkt als „neu“ gilt.
    Standardwert: `14`.
    Typischer Einsatz für Badges oder Hervorhebungen im Frontend („Neu“, „Just arrived“, „Neu im Sortiment“). | ## `content.productType` - Produkttypen Der Knoten `content.productType` dient zur Definition von Produkttypen, über die sich unterschiedliche Produktarten im System klassifizieren lassen. Produkttypen können verwendet werden, um Funktionen, Prozesse oder Darstellungslogiken abhängig vom Typ zu steuern, beispielsweise zur Unterscheidung zwischen physischen Produkten, digitalen Gütern oder Dienstleistungen. Jeder Produkttyp besitzt eine eindeutige ID und einen Namen, der im Admin Interface angezeigt wird. Neue Produkttypen können über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) erstellt werden. #### Beispielkonfiguration `content.productType.digital` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "digital", "name": "Digital" } ``` In diesem Beispiel wird der Produkttyp „Digital“ mit der technischen ID `digital` definiert.
    Er kann anschließend bei Produkten verwendet werden, um beispielsweise digitale Inhalte von physischen Waren zu unterscheiden. #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | `string` | Technische, eindeutige Kennung des Produkttyps, beispielsweise `"physical"`, `"digital"` oder `"service"`.
    Wird als Referenz in Produktobjekten verwendet. | | `name` | `string` | Anzeigename des Produkttyps im Admin Interface.
    Dient der besseren Lesbarkeit und kann frei gewählt werden. | ## `content.usedFields` - Zuordnung benutzerdefinierter Felder Der Knoten `content.usedFields` legt fest, welche benutzerdefinierten Felder (customCategoryField / customProductField) im Shopsystem aktiv für bestimmte Funktionsbereiche genutzt werden. Damit wird definiert, welche Custom-Felder im Frontend oder im Backend für SEO, Metadaten, Cross-Selling, Rabatte, Gutscheine usw. herangezogen werden. Das bedeutet:
    Ein hier hinterlegter Verweis wie `"metaTitle": "content.customProductField.metaTitle"`
    definiert, welches benutzerdefinierte Feld tatsächlich das SEO-Titel-Feld für Produkte ist. Dadurch können Administratoren und Entwickler individuelle Felder flexibel in die Systemlogik einbinden, ohne dass feste Systemfelder nötig sind. Die Zuordnung kann über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) erstellt und bearbeitet werden. #### Beispielkonfiguration `content.usedFields` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "categories": { "alternativeTemplate": "content.customCategoryField.alternativeTemplate", "defaultSort": null, "metaDescription": "content.customCategoryField.metaDescription", "metaDescriptionSetManually": "content.customCategoryField.metaDescriptionSetManually", "metaTitle": "content.customCategoryField.metaTitle", "metaTitleSetManually": "content.customCategoryField.metaTitleSetManually", "robotsNoFollow": "content.customCategoryField.robotsNoFollow", "robotsNoIndex": "content.customCategoryField.robotsNoIndex" }, "products": { "bestPrice": null, "commission": "content.customProductField.commission", "commissionTaxRate": "content.customProductField.commissionTaxRate", "crossSelling": "content.customProductField.crossSelling", "customNumber": "content.customProductField.customNumber", "mainCategory": "content.customProductField.mainCategory", "maxQuantity": null, "metaDescription": "content.customProductField.metaDescription", "metaDescriptionSetManually": "content.customProductField.metaDescriptionSetManually", "metaTitle": "content.customProductField.metaTitle", "metaTitleSetManually": "content.customProductField.metaTitleSetManually", "oneTimeFee": "content.customProductField.oneTimeFee", "oneTimeFeeTaxRate": "content.customProductField.oneTimeFeeTaxRate", "orderExportFields": null, "productDiscount": "content.customProductField.productDiscount", "productDiscountAbsolute": "content.customProductField.productDiscountAbsolute", "productType": "content.customProductField.productType", "ratingPoints": null, "robotsNoFollow": "content.customProductField.robotsNoFollow", "robotsNoIndex": "content.customProductField.robotsNoIndex", "validForDiscount": "content.customProductField.validForDiscount", "validInsertCodes": "content.customProductField.validInsertCodes", "voucherProductActive": "content.customProductField.voucherProductActive", "voucherProductCharge": "content.customProductField.voucherProductCharge", "voucherProductHtmlTemplate": "content.customProductField.voucherProductHtmlTemplate", "voucherProductPrice": "content.customProductField.voucherProductPrice", "weight": "content.customProductField.weight", "freeShipping": "content.customProductField.freeShipping" } } ``` In diesem Beispiel sind bestimmte Custom-Felder für SEO, Preise, Gewicht, Gutscheine und Cross-Selling explizit zugeordnet. Andere Felder wie `bestPrice` oder `defaultSort` bleiben ungenutzt (`null`). Der Slot `setOrgPrice` ist entfallen. Der Referenzpreis eines Set-Produkts wird nicht mehr in einem Produktfeld gespeichert, sondern bei jedem Aufruf berechnet. Im Template steht er als `setOrgPrice` am Produktobjekt zur Verfügung, siehe [Preise von Set-Produkten](/frontend/referenz/module/wsproducts#preise-von-set-produkten). #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------------------- | --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `categories` | `object` | Enthält alle Zuordnungen, die für Kategoriefelder gelten, beispielsweise SEO-Texte, Templates und Robots-Angaben. | | `alternativeTemplate` | `singleAssoc `
    `→ content.customCategoryField` | Referenz auf ein Feld, das alternative Template-Pfade oder Layouts definiert. | | `defaultSort` | `singleAssoc `
    `→ content.customCategoryField` | Legt die Standard-Sortierung innerhalb einer Kategorie für die interne Suche fest.
    Der Wert muss den Namen einer konfigurierten Sortieroption aus `search.productSortOption` enthalten. | | `metaDescription` | `singleAssoc `
    `→ content.customCategoryField` | Feld für SEO-Beschreibung der Kategorie. | | `metaDescriptionSetManually` | `singleAssoc `
    `→ content.customCategoryField` | Kennzeichnet für die SEO-Felder, ob ihr Inhalt manuell gepflegt oder automatisch erzeugt wird.
    Standardmäßig befüllt der SEO-Dienst diese Werte automatisch. In der Konfiguration wird einmalig zugewiesen, aus welchen Feldern die Generierung erfolgt. | | `metaTitle` | `singleAssoc `
    `→ content.customCategoryField` | Feld für SEO-Titel der Kategorie. | | `metaTitleSetManually` | `singleAssoc `
    `→ content.customCategoryField` | Steuerfeld für den SEO-Titel, ob die Werte manuell gesetzt oder automatisch generiert wurden. | | `robotsNoFollow` | `singleAssoc `
    `→ content.customCategoryField` | Verweis auf ein Custom-Field (Boolean), das steuert, ob Suchmaschinen Links auf dieser Seite folgen dürfen.
    `true` - “`nofollow`" für diese Seite aktiviert `false` - Links werden von Suchmaschinen indexiert | | `robotsNoIndex` | `singleAssoc `
    `→ content.customCategoryField` | Verweis auf ein Custom-Feld (Boolean), das steuert, ob die Seite indexiert werden darf.
    `true` - `noindex`(Seite nicht indexieren)
    `false`- Seite darf indexiert werden. | | `products` | `object` | Enthält alle Zuordnungen, die für Produktfeldeigenschaften gelten, beispielsweise Preise, Gutscheininformationen, Cross-Selling und SEO.
    Ordnet Custom-Felder zu, die für Produkte verwendet werden. | | `bestPrice` | `singleAssoc `
    `→ content.customProductField` | Optionales Feld für die günstigste Preisoption oder Vergleichspreise. | | `commission` | `singleAssoc `
    `→ content.customProductField` | Provisionsfelder für den Verkauf, beispielsweise für Partnerprogramme. | | `commissionTaxRate` | `singleAssoc `
    `→ content.customProductField` | Provisionsfelder für den Verkauf, beispielsweise für Partnerprogramme. | | `crossSelling` | `singleAssoc `
    `→ content.customProductField` | Feld für Cross-Selling- oder Zubehörverknüpfungen. | | `customNumber` | `singleAssoc `
    `→ content.customProductField` | Alternative Artikelnummer. | | `mainCategory` | `singleAssoc `
    `→ content.customProductField` | Verweist auf ein Custom-Feld, das die Hauptkategorie eines Produkts enthält.
    Diese wird unter anderem genutzt für den SEO-URL-Pfad (übergeordnete Kategorie im Link) oder Breadcrumbs beim Direkteinstieg auf die Produktseite. | | `metaDescription` | `singleAssoc `
    `→ content.customProductField` | SEO-Feld für Produktbeschreibung. | | `metaDescriptionSetManually` | `singleAssoc `
    `→ content.customProductField` | Steuerfeld für manuell gesetzte SEO-Werte. | | `metaTitle` | `singleAssoc`
    `→ content.customProductField` | SEO-Feld für Produkttitel. | | `metaTitleSetManually` | `singleAssoc `
    `→ content.customProductField` | Steuerfeld für manuell gesetzte SEO-Werte. | | `oneTimeFee` | `singleAssoc `
    `→ content.customProductField` | Zusatzgebühren wie beispielsweise eine Servicepauschale und deren Steuerinformationen. | | `oneTimeFeeTaxRate` | `singleAssoc `
    `→ content.customProductField` | Zusatzgebühren wie beispielsweise eine Servicepauschale und deren Steuerinformationen. | | `orderExportFields` | `multiAssoc `
    `→ content.customProductField` | Liste zusätzlicher Felder, die beim Bestellexport mitgegeben werden. | | `productDiscount` | `singleAssoc `
    `→ content.customProductField` | Felder zur Steuerung von Rabattinformationen (prozentual / absolut).
    Dieser Rabatt gilt nur für Set-Produkte. | | `productDiscountAbsolute` | `singleAssoc `
    `→ content.customProductField` | Felder zur Steuerung von Rabattinformationen (prozentual / absolut).
    Dieser Rabatt gilt nur für Set-Produkte. | | `productType` | `singleAssoc `
    `→ content.customProductField` | Zuweisung eines Custom-Felds für Produkttyp-Informationen. | | `ratingPoints` | `singleAssoc `
    `→ content.customProductField` | Feld für Bewertungs- oder Punktesysteme. | | `robotsNoFollow` | `singleAssoc `
    `→ content.customProductField` | Suchmaschinensteuerung (Indexierung / Follow). | | `robotsNoIndex` | `singleAssoc `
    `→ content.customProductField` | Suchmaschinensteuerung (Indexierung / Follow). | | `validForDiscount` | `singleAssoc `
    `→ content.customProductField` | Steuerung, ob ein Produkt für Rabattaktionen berücksichtigt wird. | | `validInsertCodes` | `singleAssoc `
    `→ content.customProductField` | Ordnet das Produktfeld zu, das die je Produkt gültigen [Werbemittelkennzeichen](/frontend/funktionsubersicht/werbemittelkennzeichnung) enthält. Ohne diese Zuordnung kann der Shop die gültigen Codes eines Produkts nicht ermitteln, und jede Position erhält den Standardcode - ohne Fehlermeldung. | | `voucherProductActive` | `singleAssoc `
    `→ content.customProductField` | Steuert, ob beim Kauf automatisch ein Gutschein (PDF) erzeugt wird. | | `voucherProductCharge` | `singleAssoc `
    `→ content.customProductField` | Referenz auf die Charge/Charge-ID, aus der ein Gutschein neu erstellt oder aus einem importierten Pool entnommen wird. | | `voucherProductHtmlTemplate` | `singleAssoc `
    `→ content.customProductField` | Name/Pfad des HTML-Templates, das zur Erzeugung des Gutschein-PDFs verwendet wird. | | `voucherProductPrice` | `singleAssoc `
    `→ content.customProductField` | Wenn aktiv, entspricht der Gutscheinwert dem Produktpreis. | | `weight` | `singleAssoc `
    `→ content.customProductField` | Feld für das Produktgewicht. | | `freeShipping` | `singleAssoc `
    `→ content.customProductField` | Wenn sich nur Produkte im Warenkorb befinden, bei denen dieses Feld auf `true` steht, werden keine Versandkosten berechnet. | ## `content.videoSettings` - Videoeinstellungen für Produkte und Kategorien Der Knoten `content.videoSettings` definiert die allgemeinen Parameter für den Upload und die Ablage von Videodateien, die in Produkt- oder Kategorieinhalten verwendet werden.
    Hierüber wird festgelegt, welche Formate zulässig sind, wie groß eine Videodatei maximal sein darf, und in welchen Zielverzeichnissen Videos gespeichert werden. Diese Einstellungen greifen sowohl bei manuellen Uploads im Admin Interface als auch bei automatisierten Datenimporten. Neue und bestehende Einstellungen können über das Admin Interface (Service „Sonstige Module → Videos“) oder über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) bearbeitet werden. #### Beispielkonfiguration `content.videoSettings` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "allowedFormats": [], "categoryTargetDirectory": "categories/video", "maxFileSize": 250, "productTargetDirectory": "products/video" } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `allowedFormats` | `list` | Liste der zugelassenen Dateiformate, beispielsweise `["mp4", "mov", "webm"]`.
    Ist die Liste leer, werden alle unterstützten Standardformate akzeptiert. | | `categoryTargetDirectory` | `string` | Zielverzeichnis für Kategorievideos.
    Standardwert: `categories/video`. | | `maxFileSize` | `int` | Maximale Dateigröße in Megabyte (MB), die beim Hochladen von Videodateien erlaubt ist.
    Standardwert: `250`. | | `productTargetDirectory` | `string` | Zielverzeichnis für Produktvideos.
    Standardwert: `products/video`. | # creditCheck - Bonitätsprüfung Source: https://dokumentation.websale.de/konfiguration/creditcheck-bonitatsprufung Konfiguration des creditCheck-Knotens für Bonitäts- und Risikoprüfungen im Checkout: Auslöseregeln, Mindestwarenkorbwerte und Provider wie creditPass. Der Konfigurationsknoten **creditCheck** bündelt alle Einstellungen für **Bonitäts- und Risikoprüfungen** im Checkout. Er steuert, **ob**, **wann** und **für wen** Prüfungen ausgelöst werden (z. B. ab einem Mindestwarenkorbwert, nur für bestimmte Länder oder Zahlungsarten) und welche **Drittanbieter** bzw. **Provider** (z. B. *creditPass*) verwendet werden. **ACHTUNG: Dieses Feature wird aktuell noch nicht unterstützt.** *** ## `creditCheck*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `creditCheck` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "creditCheck": { "creditPass": {...} } } ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | --------------------------------------------------------------------------------------- | | `creditPass` | Bindet einen Anbieter für Kredit-/Bonitätsprüfungen ein und konfiguriert die Anbindung. | *** ## `creditCheck.creditPass` - Anbindung des Anbieters Der Knoten `creditPass` steuert die Anbindung eines externen Bonitäts- bzw. Risikoprüfungsdienstes. Hier wird unter anderem festgelegt, ob die Prüfung aktiv ist, unter welcher URL der Dienst angesprochen wird und mit welchen Zugangsdaten sich der Shop authentifiziert. Beispielkonfiguration: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "url": "https://api.creditpass.de/check", "authId": "MEIN_SHOP_ID", "authPw": "geheimesPasswort123", "taType": 1, "countries": [ "general.country.de", "general.country.at" ], "minTotalPrice": 50.00 } ``` **Parameterübersicht** | **Parameter** | **Typ** | **Beschreibung** | | --------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `active` | bool | Schaltet die Anbindung an den Kredit-/Bonitätsdienst ein oder aus.
    `false` = es werden keine creditPass-Prüfungen durchgeführt. | | `url` | string | Endpunkt-URL des externen Dienstes, an den die Bonitäts-/Risikoprüfungsanfragen gesendet werden. | | `authId` | string | Benutzer-/Konto-ID für die Authentifizierung beim Anbieter. | | `authPw` | string | Passwort/Secret für die Authentifizierung beim Dienstanbieter. | | `taType` | int | Kennzahl für den Transaktionstyp, der beim Anbieter verwendet wird. | | `countries` | multiAssoc | Liste der Länder, für die eine creditPass-Prüfung durchgeführt werden soll.
    Target: `general.country` | | `minTotalPrice` | float | Mindest-Gesamtbetrag des Warenkorbs, ab dem eine Prüfung ausgelöst wird. | # customer - Kundendaten Source: https://dokumentation.websale.de/konfiguration/customer-kundendaten Der customer-Knoten konfiguriert Erfassung von Kundendaten: Adressfelder, Pflichtangaben, Feldgruppen, Validierung sowie Speicherort im Konto oder Bestellung. Der Konfigurationsknoten `customer` bündelt alle Einstellungen rund um die Erfassung und Verarbeitung von Kundendaten im Onlineshop.\ Er definiert, welche Informationen im Kundenkonto und im Checkout abgefragt werden, wie diese Felder benannt, gruppiert, validiert und als Pflichtangaben markiert sind – inklusive Steuerung des Speichertyps (im Konto, in der Bestellung oder beides).\ Darüber hinaus ermöglicht er die Strukturierung der Formulare über Feldgruppen sowie globale Anzeige- und Speicherregeln für zusätzliche Kundendatenfelder. ## `customer*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `customer` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "customer": { "customerDataField": {...}, "customerDataFieldSettings": {...}, "customerDataGroup": {...} } } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | --------------------------- | ----------------------------------------------------------------- | | `customer` | Verwaltet Kundendaten und Kontofunktionen im Shop. | | `customerDataField` | Konfigurierbares Kundendatenfeld. | | `customerDataFieldSettings` | Einstellungen für Anzeige und Speicherung von Kundendatenfeldern. | | `customerDataGroup` | Fasst mehrere Kundendatenfelder zu einem Abschnitt zusammen. | ## `customer.customerDataField` - Kundendatenfelder Definiert frei konfigurierbare Felder für Kundendaten – inklusive Label, Pflichtstatus und Speicherort. Unterstützt verschiedene Feldtypen (Text, Zahl mit Einheiten, Datum, Checkbox, Auswahl) mit Defaults, Wertebereichen und Validierungen. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "companyName", "label": "", "required": true, "uniqueValue": false, "storageStrategy": "account", "type": { "text": { "default": "" } }, "validations": [ { "service": "inputValidation.minLength", "options": { "len": 2 } }, { "service": "inputValidation.maxLength", "options": { "len": 80 } } ] } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | -------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string (unique) | Technischer Name des Feldes. Muss eindeutig sein und ist selbst wählbar. | | `label` | string | Anzeigename auf der Benutzeroberfläche.

    | | `required` | bool | Markiert das Feld als Pflichtfeld.
    Default: **false** | | `uniqueValue` | bool | Legt fest, ob der Wert des Feldes shopweit eindeutig sein muss (`true`). Ist die Option aktiv, wird das Feld bei der Duplettenprüfung (`accounts.account` → `duplicate`, siehe [accounts - Benutzerkonten](/konfiguration/accounts-benutzerkonten)) herangezogen – z.B. für die USt-IdNr.
    Default: **false** | | `accountMemberField` | bool | Bestimmt, ob das Feld beim Firmenkonto oder bei Mitarbeiterkonten gespeichert wird. | | `storageStrategy` | enum | Speicherort der Werte - im Konto, nur in der Bestellung oder beides.
    Mögliche Werte:
    - `account`
    - `order`
    - `hybrid`
    Default: **account** | | `type` | oneOf | Feldtyp für Detailkonfigurationen. | | `text` | object | Texteingabefeld | | `default` | string | Vorbelegung des Textfelds. **(optional)** | | `number` | object | Numerisches Eingabefeld. | | `default` | int | Vorbelegung des Eingabefelds **(optional)**. | | `min` | int | Minimal zulässiger Wert. **(optional)** | | `max` | int | Maximal zulässiger Wert. **(optional)** | | `step` | int | Schrittweite des Wertes bei Eingabe
    Default: **1** | | `numDecimals` | int | Anzahl der Nachkommastellen.
    Default: **0** | | `unit` | oneOf | Einheitsdefinition **(optional)** | | `constant` | object | Feste, nicht veränderbare Einheit. | | `name` | string | Technischer Name der Einheit. | | `label` | string | Anzeige-Label der Einheit.

    | | `dynamic` | object | Basiseinheit + auswählbare Einheit. | | `baseUnitName` | string | Name der Basiseinheit. | | `unitOptions` | list (object) | Liste verfügbarer Einheiten. | | `name` | string | Technischer Name der Einheit. | | `label` | string | Anzeige-Label der Einheit.

    | | `factor` | float | Umrechnungsfaktor. | | `converter` | singleService | Externer Konverter für die Umrechnung **(optional)**.
    Aktuell gibt es hier nur den `unitConverter.orderOfMagnitude`. | | `freeSelection` | object | Freie Auswahl an festen Optionen. | | `unitOptions` | list (object) | Wählbare Einheiten. | | `name` | string | Technischer Name. | | `label` | string | Anzeige-Label.

    | | `defaultOptionName` | string | Vorbelegung der Einheit. | | `date` | object | Datumsfeld. | | `default` | string | Vorbelegung (optional). | | `checkbox` | object | Checkbox. | | `default` | bool | Vorbelegung der Checkbox.
    Default: false | | `select` | object | Auswahlliste (Dropdown). | | `options` | list (object) | Verfügbare Auswahlwerte. | | `value` | string | Technischer Wert einer Option. | | `label` | string | Anzeige-Label der Option.

    | | `default` | string | Vorbelegte Option **(optional)** | | `validations` | multiService | Liste von Validierungsregeln.
    Beispiel: - `minLength` - `maxLength` - mehr unter [Validierungs- und Prüfservices](/konfiguration/validierungs-und-prufservices)
    Target: `inputValidation` | ## `customer.customerDataFieldSettings` - Feldkonfiguration Steuert, wie zusätzliche Kundendatenfelder im Shop angezeigt und gespeichert werden. Ungruppierte Felder können optional eingeblendet werden, und Kontofelder lassen sich zusätzlich in der Bestellungen speichern. Darüber hinaus wird hier festgelegt, welche Felder bei der Neu- bzw. Bestandskundenregistrierung abgefragt werden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "showUngroupedFields": true, "storeAccountFieldsInOrder": false, "newCustomerFields": [ "customer.customerDataField.neukundenfeld1", "customer.customerDataField.neukundenfeld2" ], "existingCustomerFields": [ "customer.customerDataField.bestandskundenfeld1", "customer.customerDataField.bestandsfeld2" ] } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `showUngroupedFields` | bool | Zeigt ungruppierte Kundendatenfelder im Formular an.
    Default: **true** | | `storeAccountFieldsInOrder` | bool | Speichert Kontofelder zusätzlich in der Bestellung.
    Default: **false** | | `newCustomerFields` | multiAssoc | Liste der Kundendatenfelder, die bei der Neukundenregistrierung abgefragt werden.
    Target: `customer.customerDataField` | | `existingCustomerFields` | multiAssoc | Liste der Kundendatenfelder, die bei der Bestandskundenregistrierung abgefragt werden.
    Target: `customer.customerDataField` | ## `customer.customerDataGroup` - Gruppierung Gruppiert frei definierte Kundendatenfelder zu einem Abschnitt (z.B. Rechnungsadresse, Unternehmensangaben). Jede Gruppe hat einen technischen Namen, ein sichtbares Label und verweist auf die enthaltenen Felder. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "company_data", "label": "", "fields": [ "customer.customerDataField.company", "customer.customerDataField.vatId", "customer.customerDataField.phone" ] } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | Technischer Name der Gruppe. Selbst wählbar. | | `label` | string | Anzeigename der Gruppe im Formular.

    | | `fields` | multiAssoc | Liste der zugeordneten Kundendatenfelder, die in dieser Gruppe angezeigt werden sollen.
    Target: `customer.customerDataField` | # E-Mails & E-Mail Einstellungen Source: https://dokumentation.websale.de/konfiguration/e-mails-e-mail-einstellungen Überblick aller vom Shop versendeten E-Mails und das einheitliche Konfigurationsprinzip (Template, Betreff, Absenderadresse, Absendername) je E-Mail-Typ. Das WEBSALE Shopsystem versendet eine Vielzahl von E-Mails zu unterschiedlichen Zwecken, zum Beispiel im Checkout, im Kundenkonto, bei Formularanfragen oder für Benachrichtigungen. Diese Seite gibt einen Überblick über alle vom Shopsystem versendeten E-Mails und beschreibt das einheitliche Konfigurationsprinzip, nach dem die einzelnen E-Mail-Typen angepasst werden können (z. B. Template, Betreff und Absenderdaten). *** ## Konfiguration eines E-Mail-Abschnitts Die Konfiguration einzelner E-Mail-Abschnitte folgt in WEBSALE einem einheitlichen Muster: Unabhängig davon, ob die E-Mail in `actions`, `inquiry`, `messages` etc. definiert ist, werden in der Regel Template, Betreff sowie Absenderdaten über dieselben Grundparameter gesteuert (z. B. `template`, `subject`, `fromAddress`, `fromName`). Im folgenden Abschnitt wird dieses Schema beschrieben und gezeigt, wie ein E-Mail-Abschnitt aufgebaut und konfiguriert wird. #### Beispielkonfiguration (aus `actions.checkoutConfirm`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "customerEmail": { "template": "order_confirmation_customer.htm", "subject": "Ihre Bestellung bei Mein Onlineshop", "fromAddress": "noreply@meinshop.de", "fromName": "Mein Onlineshop", "merchantEmail": "bestellungen@meinshop.de", "attachments": [ { "name": "AGB.pdf", "file": "/files/agb.pdf" } ] } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `active` / `enabled` | bool | Aktiviert/deaktiviert den Versand der E-Mail, sofern der Parameter in der jeweiligen E-Mail-Konfiguration vorhanden ist. Bei bestimmten E-Mails (z. B. rechtlich notwendigen Systemmails wie Bestelleingangsbestätigungen) ist keine Deaktivierung vorgesehen, dort sind die Parameter `enabled` oder `active` nicht zulässig. | | `attachments` | array (object) | Liste von Dateianhängen, die mit der E-Mail versendet werden sollen. Je Anhang sind `name` und `file` anzugeben. Optionale Angabe. Nicht in jedem E-Mail-Abschnitt verfügbar. | | `fromAddress` | string | Absenderadresse, die im E-Mail-Versand versendet wird (z. B. `noreply@mein-shop.de`). | | `fromName` | string | Anzeigename des Absenders in der E-Mail (z. B. „Mein Onlineshop"). | | `mail` | string | Empfängeradresse, an die die E-Mail versendet wird. Bei bestimmten E-Mails ist dieser Parameter nicht vorgesehen, da der Versand dynamisch an eine im Shop angegebene E-Mail-Adresse erfolgt. | | `merchantEmail` | string | Optionale Möglichkeit, eine zusätzliche Benachrichtigung/Kopie an eine definierte Händleradresse zu senden. Dieser Parameter ist nur bei bestimmten E-Mails vorgesehen und nicht bei allen E-Mails konfigurierbar. | | `template` | string | Name der zu verwendenden E-Mail-Vorlage (Dateiname, ggf. mit Unterpfad innerhalb von `mails/`). Darüber werden Inhalt und Layout der E-Mail gesteuert.
    Das Verzeichnis `mails/` wird vom System automatisch vorangestellt - siehe Hinweis unten. | | `subject` / `mailSubject` | string | Betreffzeile der E-Mail, wie sie im Posteingang des Kunden angezeigt wird. | *** ## E-Mail-Template-Verzeichnis Alle E-Mail-Templates liegen im Verzeichnis `templates/mails/`. Dieses Verzeichnis ist fest vorgegeben und wird beim `template`-Parameter automatisch vorangestellt. Geben Sie deshalb nur den Dateinamen an, ohne das Präfix `mails/`. Beispiel: Die Vorlage `templates/mails/password_forgotten.htm` wird so referenziert. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "email": { "template": "password_forgotten.htm", "subject": "Passwort zurücksetzen", "fromAddress": "noreply@meinshop.de", "fromName": "Mein Onlineshop" } ``` Der Grund für die Angabe ohne Präfix: Da `mails/` automatisch ergänzt wird, führt ein zusätzlich angegebenes `mails/` dazu, dass die Vorlage nicht gefunden wird. Die E-Mail wird in diesem Fall nicht versendet. Das Verzeichnis `mails` kann nicht umbenannt oder verschoben werden. Es ist ein festes Spezial-Verzeichnis der Template-Struktur (siehe [Template Theme](/frontend/die-basics/template-theme)). Eigene Unterordner innerhalb von `mails` werden für den `template`-Parameter nicht unterstützt. Eine Vorlage, die in einem Unterordner liegt (zum Beispiel `templates/mails/login/password_forgotten.htm`), ist über den `template`-Parameter nicht ansprechbar. Legen Sie Mail-Templates daher direkt in `mails/` ab. *** ## E-Mail-Benachrichtigungen im Überblick Im Folgenden findet sich eine Übersicht der E-Mails, die vom Shopsystem versendet werden. Diese E-Mails können nach dem oben beschriebenen Schema konfiguriert werden (z. B. Absender, Betreff und Template). | **E-Mail** | **Konfiguration** | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | **Bestelleingangsbestätigungs-E-Mail an den Käufer** — Bestätigung des Bestelleingangs an den Kunden. Auslöser: Bestellabschluss / Kunde. Optional kann diese E-Mail zusätzlich als Kopie an eine konfigurierte Händleradresse (`merchantEmail`) versendet werden. | [actions.checkoutConfirm](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout#2-3-actions-checkoutconfirm-bestellung-abschließen) | | **Bewertungserinnerungs-E-Mail** — Erinnerung zur Abgabe einer Produktbewertung nach dem Kauf. Konfiguration im Admin Interface unter *Marketing → Kundenbewertungen*. | [general.productRating](/konfiguration/general-allgemeine-shopeinstellungen#general-productrating-produktbewertung) → `reminderEmail` | | **Benachrichtigung über neue Produktbewertung (Händler)** — E-Mail an den Händler zur Information über eine neu abgegebene Produktbewertung. | [actions.productRatingAdd](/konfiguration/actions-fehlertexte-e-mails/actions-produkte#3-1-actions-productratingadd-produkt-bewerten) | | **Double-OptIn-E-Mail bei E-Mail-Adressänderung** — Optionale Double-Opt-In-E-Mail, bevor die neue E-Mail-Adresse übernommen wird. | [actions.emailUpdate](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto#6-1-actions-emailupdate-e-mail-adresse-ändern) | | **Bestätigungs-/Verify-E-Mail bei E-Mail-Adressänderung** — Bestätigungs-/Verify-E-Mail an die neue Adresse (Bestätigungslink). | [actions.emailUpdate](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto#6-1-actions-emailupdate-e-mail-adresse-ändern) | | **Double-OptIn-E-Mail bei Kundenkonto löschen** — Optionale Double-Opt-In-E-Mail zur Bestätigung des Löschwunsches vor Ausführung. | [actions.accountDelete](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto#2-1-actions-accountdelete-kontolöschung) | | **Bestätigung zum Löschen des Kundenkontos** — Bestätigungs-E-Mail, dass das Kundenkonto gelöscht worden ist. | [actions.accountDelete](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto#2-1-actions-accountdelete-kontolöschung) | | **Eingangsbestätigung Formular (Anfragender)** — Bestätigung, dass die Anfrage eingegangen ist (z. B. Kontaktformular). Optional kann diese E-Mail zusätzlich als Kopie an eine konfigurierte Händleradresse (`merchantEmail`) versendet werden. | [inquiry.form](/konfiguration/inquiry-formulare#inquiry-formulare) | | **Registrierungsbestätigung (Verifizierungsmail)** — E-Mail zur Verifizierung der Registrierung bzw. Bestätigung der E-Mail-Adresse nach dem Anlegen eines Kundenkontos. | [actions.accountRegister](/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto#2-3-actions-accountregister-benutzer-registrieren) | | **Dublette bei Registrierung gefunden** — Information an ein bereits vorhandenes (Dubletten-)Konto, wenn bei einer Registrierung eine Dublette erkannt wird. Im E-Mail-Template ist über `$wsRequestVariables.email` die bei der Registrierung angegebene Adresse ausgebbar (z. B. damit der Account-Admin ein Subaccount für den Nutzer anlegen kann). | [accounts.account](/konfiguration/accounts-benutzerkonten) → `duplicate.foundEmail` | | **Ereignisgesteuerte/individuelle Benachrichtigungen** — Zusätzliche E-Mails können definiert werden, die beim Aufruf bestimmter Shopseiten oder beim Ausführen definierter Aktionen versendet werden. | [messages.emails](/konfiguration/messages-ereignisgesteuerte-e-mails#2-messages-emails-ereignisgesteuerte-e-mails) | | **Wieder-verfügbar-Benachrichtigung (Back in Stock)** — E-Mail an den Kunden, sobald ein zuvor nicht verfügbarer Artikel wieder lieferbar ist. | [content.inventory](/konfiguration/content-katalog-kategorien-produkte#beispielkonfiguration-content-inventory) | | **Lagerbestandsmitteilung (Bestandswarnung)** — E-Mail an den Händler mit einer Übersicht über Artikel mit niedrigem Bestand (bis zur konfigurierten Anzahl), versendet an eine definierte Empfängeradresse. | [content.inventory](/konfiguration/content-katalog-kategorien-produkte#beispielkonfiguration-content-inventory) | | **Zahlung fehlgeschlagen (Kunde)** — E-Mail an den Kunden mit Hinweis, dass die Zahlung zur Bestellung fehlgeschlagen ist. Optional kann diese E-Mail zusätzlich als Kopie an eine konfigurierte Händleradresse (`merchantEmail`) versendet werden. | [actions.checkoutConfirm](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout#2-3-actions-checkoutconfirm-bestellung-abschließen) | Hinweis: Einige System-E-Mails sind rechtlich bzw. funktional notwendig und können daher ggf. nicht deaktiviert werden. # finance - Währungen & Steuern Source: https://dokumentation.websale.de/konfiguration/finance-wahrungen-steuern Der finance-Knoten bündelt shopweite Einstellungen zu Währungen, Preisformatierung, Brutto-/Netto-Logik, Steuersätzen sowie Zuschlägen wie Pfand und Abgaben. Der Konfigurationsknoten `finance` bündelt alle shopweiten Einstellungen zu **Währungen**, **Steuern** und **Steuersätzen**.\ Er definiert, in welcher **Währung** Preise ausgegeben und **formatiert** werden, ob Preise **inklusive** oder **exklusive** Steuer geführt sind und nach welcher **Berechnungslogik** die Steuer ermittelt wird.\ Zudem werden hier die **Steuersätze** (z. B. nach Land/Region oder Kategorie) festgelegt sowie **optionale Zuschläge** wie Pfand oder Abgaben konfiguriert. *** ## `finance*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `finance` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "finance": { "currency": { ... }, "taxes": { ... }, "taxRates": { ... }, "taxRatesAddition": { ... }, "exchangeRates": { ... }, "shopRent": { ... }, "shopRentTier": { ... } } } ``` #### Parameterbeschreibung | **Parameter** | **Beschreibung** | | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `currency` | Definiert die Währungs- und Formatierungseinstellungen des Shops.
    Hier werden Code (z. B. „EUR“), Symbol, Dezimalstellen und Trennzeichen angegeben.
    Werte in Textform oder numerisch. | | `taxes` | Steuert die grundlegende Steuerlogik des Shops.
    Enthält Parameter wie Preisbasis (`gross` / `net`), Anzeigeart (`pricesIncludeTaxes` = true/false) und Versandsteuer (`shippingTaxDeductible` = true/false).
    Werte als Schlüssel-Wert-Paare. | | `taxRates` | Enthält die länderspezifischen Steuersätze in Listenform.
    Jeder Eintrag enthält eine ID (z. B. „standard“), den Prozentsatz (`rate`) und optionale Zuordnungen (`appliesTo`).
    Struktur: Objekt mit Länderkennzeichen als Schlüssel, Array als Wert. | | `taxRatesAddition` | Optionale Zusatzsteuern oder Abgaben (z. B. Pfand). Aufbau analog zu `taxRates`, meist mit Feldern wie `type` („fixed\_per\_unit“ / „percent“), `value` (Zahl) und `appliesTo` (Liste von Artikelgruppen). | | `exchangeRates` | Steuert das Verhalten des automatischen Wechselkursabrufs.
    Definiert Abrufzeitpunkt, Wartezeit und Umgang mit veralteten oder nicht verfügbaren Kursen. | | `shopRent` | Konfiguriert den Abrechnungszeitpunkt der Shop-Miete.
    Enthält die Stichzeit am Monatsersten sowie Verweise auf die zugehörigen Preisstaffelungen. | | `shopRentTier` | Definiert einzelne Preisstaffelungen für die Shop-Miete mit Tarif, Volumenobergrenze und monatlicher Grundgebühr. | *** ## `finance.currency` - Währungen Im Abschnitt `currency` werden eine oder mehrere Währungen definiert, die im Shop verfügbar sein sollen. Jede Währung wird als eigener Unterknoten angelegt und enthält Formatierungsregeln und ISO-Angaben. Über diese Definitionen werden Symbol, Schreibweise und Trennzeichen festgelegt, die später im Frontend bei der Preisdarstellung verwendet werden. Die Zuordnung, welche Währung ein Subshop tatsächlich verwendet, erfolgt in der Subshop-Konfiguration #### Beispielkonfiguration für EURO (`finance.currency.euro`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "decimalPlaces": 2, "decimalSeparator": ",", "isoCode": "EUR", "isoNum": "978", "symbol": "€", "symbolPosition": "right", "thousandsSeparator": "." } ``` #### Beispielkonfiguration für BRITISCH PFUND (`finance.currency.britishpound`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "decimalPlaces": 2, "decimalSeparator": ".", "isoCode": "GBP", "isoNum": "826", "symbol": "£", "symbolPosition": "left", "thousandsSeparator": "," } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | -------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `decimalPlaces` | int | Anzahl der Nachkommastellen, die für Preise angezeigt werden (z. B. 2 → „19,99 €“). | | `decimalSeparator` | string | Zeichen zur Trennung von Ganz- und Nachkommastellen (z. B. `","` oder `"."`). | | `thousandsSeparator` | string | Zeichen zur Trennung von Tausendern (z. B. `"."` oder `","`). | | `symbol` | string | Währungssymbol, das im Shop angezeigt wird (z. B. `"€"`, `"£"`, `"$"`). | | `symbolPosition` | enum | Position des Symbols relativ zum Betrag. Mögliche Werte: `left` (z. B. „£19.99“) oder `right` (z. B. „19,99 €“). | | `isoCode` | string | Dreistelliger [ISO-4217-Code](https://www.iso.org/iso-4217-currency-codes.html) der Währung (z. B. `"EUR"`, `"GBP"`, `"CHF"`). Wird systemintern zur Identifikation verwendet. | | `isoNum` | string | Numerischer [ISO-4217-Code](https://www.iso.org/iso-4217-currency-codes.html) der Währung (z. B. `978` = Euro, `826` = Pfund). Wird für internationale Prozesse und API-Kommunikation genutzt. | *** ## `finance.taxRates` - Steuersätze Im Abschnitt `taxRates` werden die konkreten Mehrwertsteuersätze pro Land oder Region definiert.\ Jeder Eintrag entspricht einem Land (z. B. `de`, `en`, `at`) und enthält eine Liste von steuerlichen Raten, die vom System für die Preisberechnung verwendet werden können. Diese Definitionen sind global verfügbar und werden in der Regel über `finance.taxes.defaultTaxRate` oder in der jeweiligen Subshop-Konfiguration referenziert. #### Beispielkonfiguration für deutsche Steuersätze (`finance.taxRates.de`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "de", "defaultTaxRate": "19", "taxRates": [ { "id": "19", "rate": 0.19 }, { "id": "7", "rate": 0.07 }, { "id": "0", "rate": 0 } ] } ``` #### Beispielkonfiguration für englische Steuersätze (`finance.taxRates.en`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "en", "defaultTaxRate": "19", "taxRates": [ { "id": "20", "rate": 0.2 }, { "id": "5", "rate": 0.05 }, { "id": "0", "rate": 0 } ] } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ---------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | Interner Bezeichner für die Steuerdefinition des Landes. Wird meist identisch zum Ländercode geführt. | | `defaultTaxRate` | string | Standard-Steuersatz-ID, die verwendet wird, wenn kein spezifischer Satz zugeordnet ist (z. B. `"19"`). | | `taxRates` | list (object) | Liste aller verfügbaren Steuersätze für dieses Land. Jeder Eintrag enthält eine eindeutige ID und den prozentualen Satz als Dezimalwert. | | `id` | string | Bezeichner des Steuersatzes (z. B. `"19"`, `"7"`, `"zero"`). Dient als Referenz innerhalb des Systems. | | `rate` | float | Steuerwert als Dezimalzahl, nicht als Prozentangabe (z. B. `0.19` = 19 %). Wird für die Preisberechnung verwendet. | *** ## `finance.taxRatesAddition` - Zusatzsteuersätze Im Abschnitt `taxRatesAddition` können zusätzliche steuerliche Aufschläge definiert werden, die ergänzend zu den regulären Mehrwertsteuersätzen gelten. Dies kann z. B. für Pfandbeträge, Umweltabgaben oder Sondersteuern genutzt werden. Jede Landesdefinition verweist dabei auf die bestehenden Steuersätze (`finance.taxRates.`) und ergänzt diese um einen oder mehrere zusätzliche Sätze. #### Beispielkonfiguration für deutsche Zusatzsteuersätze (`finance.taxRatesAddition.de`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "additionalTaxRates": [ { "id": "30", "rate": 0.3 } ], "id": "de", "taxRates": "finance.taxRates.de" } ``` #### Beispielkonfiguration für englische Zusatzsteuersätze (`finance.taxRatesAddition.en`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "additionalTaxRates": [ { "id": "luxury", "rate": 0.25 }, { "id": "environment", "rate": 0.10 } ], "id": "en", "taxRates": "finance.taxRates.en" } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | -------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------- | | `id` | string | Bezeichner der Steuerdefinition des Landes, meist identisch mit dem Ländercode. | | `taxRates` | singleAssoc | Referenz auf die regulären Steuersätze, auf denen die Zusatzsteuern aufbauen (z. B. `"finance.taxRates.de"`). | | `additionalTaxRates` | list (object) | Liste zusätzlicher Steuersätze, die zusätzlich zu den regulären angewendet werden können. | | `id` | string | Eindeutiger Bezeichner der Zusatzsteuer (z. B. `"30"`, `"luxury"`, `"environment"`). | | `rate` | float | Steuer- oder Aufschlagswert als Dezimalzahl (z. B. `0.10` = 10 %). Wird zusätzlich zum regulären Satz berechnet. | *** ## `finance.taxes` - Steuerberechnung Der Abschnitt `finance.taxes` definiert die Berechnungslogik und die Zuweisung der Steuersätze, die im jeweiligen Shop oder Subshop verwendet werden. Hier wird festgelegt, * ob Preise inklusive oder exklusive Steuer geführt werden, * welche Steuersätze aus der Konfiguration `finance.taxRates` verwendet werden, * und wie Haupt- und Nebenleistungen (z. B. Produkte, Versand) steuerlich berechnet werden. * ob die MwSt. für Versandkosten, Zahlungsartenkosten und Mindermengenzuschläge abziehbar ist. * nach welchem Modus eine länderbasierte Steuerbefreiung greift. Damit bildet dieser Abschnitt die Verknüpfung zwischen den definierten Steuersätzen (`finance.taxRates`) und der praktischen Anwendung für den Subshop. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "ancillaryServicesCalculation": "static", "ancillaryServicesTaxRate": "19", "defaultTaxRate": "finance.taxRates.de", "mainServicesCalculation": "vertical", "pricesIncludeTaxes": true, "shippingTaxDeductible": true, "paymentTaxDeductible": true, "surchargeTaxDeductible": false, "usedTaxes": "finance.taxRates.de", "countryTaxMode": "exemptList", "countryList": ["general.country.de", "general.country.at"], "countryTaxAddressMatching": "shippingAndBilling" } ``` #### Parameterbeschreibung | **Property** | **Typ** | **Beschreibung** | | ------------------------------ | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `pricesIncludeTaxes` | bool | Legt fest, ob Produktpreise **inklusive Steuer (true)** oder **exklusive Steuer (false)** geführt werden. | | `defaultTaxRate` | singleAssoc | Referenz auf die Standard-Steuersatzdefinition. Typischerweise verweist dieser Eintrag auf einen Knoten unter `finance.taxRates` (z. B. `finance.taxRates.de`). | | `usedTaxes` | singleAssoc | Gibt an, welche Steuersätze aus der `taxRates`-Konfiguration aktiv im Shop verwendet werden sollen.
    Kann ein oder mehrere Verweise enthalten. | | `mainServicesCalculation` | enum | Definiert die steuerliche Berechnungsmethode.
    Beispielwerte: `horizontal` (Berechnung je Position) oder `vertical` (Berechnung auf Gesamtbetrag). | | `ancillaryServicesCalculation` | enum | Definiert die Berechnungslogik für Nebenleistungen (z. B. Versand).
    Mögliche Werte:
    - `static` - fester Steuersatz
    - `distributed` - anteilig zur Warensteuer
    - `highestCost`- Steuersatz mit dem höchsten Warenwert | | `ancillaryServicesTaxRate` | string | Fester Prozentsatz für Nebenleistungen (z. B. Versandkostensteuer = „19“).
    Wird nur verwendet, wenn `ancillaryServicesCalculation = "static"` ist. | | `shippingTaxDeductible` | bool | Legt fest, ob die Mehrwertsteuer für Versandkosten abziehbar ist (`true`) oder nicht (`false`). | | `paymentTaxDeductible` | bool | Legt fest, ob die Mehrwertsteuer für Zahlungsartenkosten abziehbar ist (`true`) oder nicht (`false`). | | `surchargeTaxDeductible` | bool | Legt fest, ob die Mehrwertsteuer für den Mindermengenzuschlag abziehbar ist (`true`) oder nicht (`false`). | | `countryTaxMode` | enum | Steuert den Modus der länderbasierten Steuerbefreiung.
    Mögliche Werte:
    - `taxableList` - nur Länder in der Liste sind steuerpflichtig (alle anderen befreit)
    - `exemptList` - nur Länder in der Liste sind steuerbefreit
    - `disabled` - Feature deaktiviert.
    Default: `disabled` | | `countryList` | multiAssoc
    -> `general.country` | Liste der Länder, auf die der gewählte `countryTaxMode` angewendet wird. | | `countryTaxAddressMatching` | enum | Bestimmt, ob nur die Lieferadresse oder Liefer- und Rechnungsadresse für die Steuerprüfung herangezogen werden.
    Mögliche Werte:
    - `shippingOnly`- nur Lieferadresse wird geprüft.
    - `shippingAndBilling` - beide Adresse müssen (je nach Modus) die Bedingung erfüllen.
    Default: `shippingOnly` | *** ## `finance.exchangeRates` - Wechselkursabruf Der Abschnitt `exchangeRates` definiert die Konfiguration des automatischen Wechselkursabrufs. Hier wird festgelegt, * zu welchem Zeitpunkt die EZB-Tageskurse veröffentlicht werden, * wie lange nach der Veröffentlichung gewartet wird, bevor der Abruf erfolgt, * und wie das System mit veralteten oder nicht verfügbaren Kursen umgeht. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "ecbRefreshTimeCET": "16:00", "enforceRateRecency": true, "fallbackToPreviousRate": true, "fetchDelayMinutes": 30, "maxRateAgeDays": 7 } ``` #### Parameterbeschreibung | **Property** | **Typ** | **Beschreibung** | | ------------------------ | ------- | ---------------------------------------------------------------------------------------- | | `ecbRefreshTimeCET` | string | Zeitpunkt (MEZ), zu dem die EZB Tageskurse veröffentlicht.
    Default: `“16:00”` | | `fetchDelayMinutes` | int | Minuten Wartezeit nach Aktualisierungszeit vor dem Abruf.
    Default: `30` | | `enforceRateRecency` | bool | Kurse ablehnen, die älter als `maxRateAgeDays` sind.
    Default: `true` | | `maxRateAgeDays` | int | Maximal zulässiges Alter eines Kurses in Tagen.
    Default: `7` | | `fallbackToPreviousRate` | bool | Älteren Kurs verwenden, wenn aktueller nicht verfügbar.
    Default: `true` | *** ## `finance.shopRent` - Abrechnungszeitpunkt Im Abschnitt `shopRent` wird der Abrechnungszeitpunkt für die Shop-Miete konfiguriert. Hier wird definiert, * zu welcher Uhrzeit am Monatsersten der Abrechnungszeitraum endet, * und welche Preisstaffelungen (`shopRentTier`) für die Abrechnung herangezogen werden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "cutoffCET": "00:30", "tiers": [ "finance.shopRentTier.starter", "finance.shopRentTier.professional", "finance.shopRentTier.enterprise" ] } ``` #### Parameterbeschreibung | **Property** | **Typ** | **Beschreibung** | | ------------ | --------------------------- | --------------------------------------------------------------------------------------- | | `cutoffCET` | string | MEZ-Stichzeit am 1. des Monats, zu der der Abrechnungszeitraum endet. | | `tiers` | multiAssoc → shopRentTier | Verweise auf die Preisstaffelungsdefinitionen, die für die Abrechnung verwendet werden. | *** ## `finance.shopRentTier` - Preisstaffelungen Im Abschnitt `shopRentTier` werden die einzelnen Preisstaffelungen für die Shop-Miete definiert. Jede Stufe legt einen prozentualen Tarif, eine Volumenobergrenze sowie eine feste monatliche Gebühr fest. Die Zuordnung der aktiven Stufen erfolgt über `finance.shopRent`. #### Beispielkonfiguration für die Stufe “Starter” (`finance.shopRentTier.starter`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "Starter", "rate": 0.02, "maxTransactionVolume": 10000, "monthsFee": 29.99 } ``` #### Beispielkonfiguration für die Stufe “Professional” (`finance.shopRentTier.professional`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "Professional", "rate": 0.015, "maxTransactionVolume": 50000, "monthsFee": 99.99 } ``` #### Parameterbeschreibung | **Property** | **Typ** | **Beschreibung** | | ---------------------- | --------------- | -------------------------------------------------------------------------------------------------------- | | `name` | string (unique) | Eindeutige Stufenbezeichnung (z.B. “Starter”, “Professional”). Dient als Referenz innerhalb des Systems. | | `rate` | float | Prozentualer Tarif für die Mietberechnung als Dezimalwert (z.B. 0.02 = 2%). | | `maxTransactionVolume` | int | EUR-Volumenobergrenze für diese Stufe. Bei Überschreitung greift die nächste Staffel. | | `monthsFee` | float | Feste monatliche Grundgebühr in EUR, unabhängig vom Transaktionsvolumen. | # general - Allgemeine Shopeinstellungen Source: https://dokumentation.websale.de/konfiguration/general-allgemeine-shopeinstellungen Der general-Knoten enthält allgemeine WEBSALE-Shopeinstellungen: Sprachen, Länder, Subshops, Kundenkonto, Sicherheit, Testmodus und Consent-Management. Der Knoten `general` bündelt sämtliche allgemeinen und systemweiten Grundeinstellungen des Onlineshops. Er ist einer der zentralsten und zugleich umfangreichsten Konfigurationsbereiche und enthält Parameter, die zahlreiche Module, Funktionen und Darstellungen des Shops beeinflussen. Im Admin Interface sind die hier zusammengeführten Einstellungen nicht unter einem einzigen Menüpunkt zu finden. Sie betreffen unterschiedliche Funktionsbereiche (z. B. Sprachen, Länder, Subshops, Consent-Management) und sind dort entsprechend thematisch gruppiert.
    Die jeweilige Zuordnung im Admin Interface wird in der Dokumentation des jeweiligen Abschnitts angegeben. Über diesen Knoten lassen sich u. a. folgende Aspekte steuern: * Aktivierungsstatus, Zeitzone und Basisparameter des Shops * Definition der verfügbaren Länder, Sprachen, Titel und Anreden * Subshop-spezifische Einstellungen (z. B. Sprache, Währung, Theme) * Cookie- und Tracking-Consent-Gruppen inkl. einzelner Dienste * Formatierungen für Preise, Mengen und Gewichte * Postleitzahl-Prüfungen pro Land * Einstellungen für Testmodus, Kundenkontolöschung und Session-Gültigkeit Der Knoten bildet somit die zentrale Konfigurationsbasis des gesamten Systems und stellt grundlegende Abhängigkeiten für viele weitere Knoten wie basket, finance, content oder customer her. ## `general*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `general`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "general": { "addressListElements": { }, "adminAccountSettings": { }, "asse": { }, "consentCookieGroup": { }, "consentCookieService": { }, "country": { }, "customerAccountSettings": { }, "deviceTypes": { }, "garbageCollection": { }, "general": { }, "language": { }, "numberFormat": { }, "order": { }, "orderSortOption": { }, "productRating": { }, "salutation": { }, "sitemap": { }, "subshop": { }, "subshopView": { }, "testMode": { }, "title": { }, "zipCodes": { } } } ``` #### Parameterbeschreibung: | **Parameter** | **Beschreibung** | | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `addressListElements` | Definiert auswählbare Listen (Dropdowns/Radio-Listen) für Adressformulare. | | `adminAccountSettings` | Anmelderichtlinien für das Admin Interface (max. Fehlversuche, Sperrzeit). | | `asse` | Konfiguration der asynchronen Server-Side-Event-Schnittstelle (ASSE) für Webhooks/Integrationen. | | `consentCookieGroup` | Gruppen (Kategorien) im Consent Layer, die mehrere Services zusammenfassen. | | `consentCookieService` | Einzeldefinition der zustimmungspflichtigen Cookie-/Tracking-Dienste im Consent Layer. | | `country` | Definiert die im Shop auswählbaren Länder inkl. ISO-Codes und Steuerzuordnung. | | `customerAccountSettings` | Verhalten bei Löschung von Kundenkonten (Soft Delete, WaWi-Abgleich). | | `deviceTypes` | Definition der erkannten Gerätetypen (Desktop, Tablet, Smartphone). | | `garbageCollection` | Gültigkeitsdauer von Sessions und automatische Bereinigung abgelaufener Sitzungen. | | `general` | Allgemeine Basisparameter (Status, Zeitzone, URL-/Referer-Parameter). | | `language` | Definiert die im System verfügbaren Sprachen. | | `numberFormat` | Formatierung von Preisen, Mengen und Gewichten (Trennzeichen, Nachkommastellen). | | `order` | Definiert optionale Bestellstatus (z. B. „in Bearbeitung", „versendet").
    Konfiguration im Admin Interface direkt im Service "*Bestellungen"* | | `orderSortOption` | Individuelle Sortieroptionen für die Bestellübersicht (Feld + Richtung). | | `productRating` | Konfiguration des Bewertungs­system für Produkte im Shop.
    Konfiguration im Admin Interface unter *Marketing → Kundenbewertungen*. | | `salutation` | Definiert die verfügbaren Anreden (z. B. Herr, Frau). | | `sitemap` | Aktiviert bzw. konfiguriert die Generierung einer Sitemap.
    Konfiguration im Admin Interface unter *SEO*. | | `subshop` | Definiert die einzelnen Subshops (ID, Sprachzuordnung, Speicherreferenz). | | `subshopView` | Basis-Einstellungen je Subshop (Sprache, Währung, Länder, Theme). | | `testMode` | Aktiviert und steuert den passwortgeschützten Testmodus des Shops. | | `title` | Definiert die verfügbaren Titel für die Anrede (z. B. Dr., Prof.). | | `zipCodes` | Syntaktische Postleitzahl-Prüfung je Land per Regex. | ## `general.addressListElements` - Adresslisten Der Knoten `general.addressListElements` definiert auswählbare Listen (Dropdowns/Radio-Listen) für Adressformulare. Jedes Listenelement besitzt eine eindeutige ID, einen technischen Namen, optional einen Anwendungsbereich (Rechnungs-/Lieferadresse) sowie die auswählbaren Werte. #### Beispielkonfiguration (`general.addressListElements.billAddressType`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "addressType": "both", "dataId": "billAddressType", "defaultValue": "1", "name": "billAddressType", "values": [ { "name": "Privat", "value": "1" }, { "name": "Firma", "value": "2" } ] } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | -------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `addressType` | enum | Optionaler Geltungsbereich der Liste.
    Zulässige Werte:
    `"bill"` (nur Rechnungsadresse), `"delivery"` (nur Lieferadresse), `"both"` (beide).
    Standard: wenn weggelassen, gilt die Liste überall, wo sie eingebunden wird. | | `defaultValue` | string | Optionaler Standardwert (String).
    Wenn gesetzt, wird dieser Wert initial vorausgewählt.
    Muss einem `values[].value` entsprechen. | | `dataId` | string | Eindeutige ID der Liste (String).
    Muss innerhalb aller Adresslisten einzigartig sein; dient der technischen Identifikation. | | `name` | string | Technischer Name der Liste (String). In der Regel analog zu `dataId`. | | `values` | list (object) | Array der auswählbaren Einträge. Reihenfolge = Anzeige-Reihenfolge. | | `name` | string | Sichtbarer Anzeigename in der UI (z. B. „Privat", „Firma"). | | `value` | string | Technischer Wert (String), der gespeichert/übertragen wird. | ## `general.adminAccountSettings` - Anmelderichtlinien für das Admin Interface Der Knoten `general.adminAccountSettings` definiert sicherheitsrelevante Vorgaben für das Admin Interface des Shops. Hier wird festgelegt, wie viele fehlgeschlagene Anmeldeversuche erlaubt sind und wie lange ein Benutzer nach Erreichen dieses Limits gesperrt bleibt, bevor ein erneuter Loginversuch möglich ist.
    Die Einstellungen dienen dem Schutz vor unbefugtem Zugriff und Brute-Force-Angriffen. #### Beispielkonfiguration (`general.adminAccountSettings`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "maxLoginAttempts": 3, "minutesToWait": 10 } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `maxLoginAttempts` | int | Maximale Anzahl an erlaubten Fehlversuchen bei der Anmeldung im Admin Interface.
    Nach Überschreiten dieses Werts wird der Benutzerzugang temporär gesperrt.
    Default: **3** | | `minutesToWait` | int | Dauer der Sperrzeit (in Minuten), bevor ein weiterer Anmeldeversuch möglich ist.
    Default: **10** | **Hinweis:** Diese Sperrung betrifft ausschließlich den Zugang zum Admin Interface und hat keine Auswirkungen auf Benutzerkonten im Frontend oder im Kundenbereich des Shops. ## `general.asse` - Schnittstelle für Asynchronous Server-Side Events (ASSE) Der Knoten `general.asse` definiert die Konfiguration der asynchronen Server-Side-Event-Schnittstelle (ASSE). Über diese Schnittstelle können serverseitige Ereignisse (Events) automatisiert an externe Systeme übermittelt werden, z. B. für Webhooks, Benachrichtigungen oder Integrationen mit Drittsystemen. #### Beispielkonfiguration (`general.asse.subscribeNewsletter2Go`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "additionalHTTPHeaders": [ { "key": "Authorization", "value": "Bearer " }, { "key": "Accept", "value": "application/json" } ], "contentType": "json", "id": "sendOrderToERP", "numberRetries": 5, "requestMethod": "post", "retryDelay": 30, "successConditions": [ { "httpStatus": 201 }, { "type": "responseJsonData", "jsonPath": "/status", "conditionType": "equal", "value": { "string": "created" } } ], "timeout": 15, "url": "https://erp.example.com/api/v2/orders" } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ----------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `additionalHTTPHeaders` | list (object) | Liste zusätzlicher HTTP-Header, die beim Request an die Ziel-URL mitgesendet werden sollen.
    Jeder Eintrag wird als Key-Value-Paar definiert.
    Falls das externe System eine Authentifizierung oder einen API-Schlüssel erwartet, kann dieser ebenfalls über `additionalHTTPHeaders` ergänzt werden, z. B.: `{ "key": "Authorization", "value": "Bearer " }` | | `contentType` | enum | Datenformat des Request-Bodys.
    Zulässige Werte: `"json"` (Standard), `"xml"` oder `"txt"`. | | `id` | string | Eindeutige Kennung der ASSE-Konfiguration, z.B. für den Prozess Newsletter-Anmeldung. | | `numberRetries` | int | Anzahl der Wiederholungsversuche, falls die Übertragung fehlschlägt.
    Default: **3** | | `payloadParameterName` | string | Optionaler Parametername, unter dem die eigentlichen Nutzdaten (Payload) übertragen werden.
    Wenn leer, wird der Payload direkt im Request-Body gesendet. | | `requestMethod` | enum | HTTP-Methode für die Übertragung.
    Typischerweise `"post"`, alternativ `"put"` ,`"patch", "get"` oder `"delete"` möglich. | | `retryDelay` | int | Zeitintervall (in Sekunden) zwischen Wiederholungsversuchen bei Fehlschlägen.
    Default: **10** | | `successConditions` | list (object) | Liste von Bedingungen, die eine erfolgreiche Übertragung kennzeichnen (z. B. erwartete HTTP-Statuscodes oder Response-Keywords). | | `timeout` | int | Maximale Wartezeit (in Sekunden) für die Serverantwort, bevor der Request abgebrochen und ggf. wiederholt wird.
    Default: **10** | | `url` | string | Ziel-URL, an die das Event gesendet wird. Muss erreichbar und für POST-/PUT-Anfragen vorbereitet sein. | ## `general.consentCookie*` - Consent Layer Es werden alle Einstellungen definiert, die den Einwilligungsdialog für Cookies, Tracking- und Analysedienste betreffen. Dieser Layer wird beim ersten Besuch des Shops angezeigt und ist gemäß DSGVO (Datenschutz-Grundverordnung) und ePrivacy-Richtlinie verpflichtend, sobald der Shop Daten des Besuchers erhebt oder externe Dienste (z. B. Tracking, Captcha, Medien-Einbindungen) nutzt. Zu den hier konfigurierten Consent-Einstellungen können ergänzend Fehlermeldungen oder Benachrichtigungstexte im Abschnitt [actions.consentChange](/konfiguration/actions-fehlertexte-e-mails/actions-sicherheit-datenschutz) definiert werden. ### `general.consentCookieGroup` - Gruppierung zustimmungspflichtiger Cookies/Trackings Der Knoten `general.consentCookieGroup` definiert die Gruppen, die im Consent Layer (Cookie-Banner) des Shops angezeigt werden, also die bekannten Kategorien wie z.B. Notwendige Cookies, Statistik oder Marketing. Jede Gruppe fasst einen oder mehrere Services zusammen. Diese Services werden separat unter `general.consentCookieService` (Punkt 5.2) angelegt und hier per Referenz zugewiesen. Die Einstellungen zu diesem Abschnitt befinden sich im Admin Interface unter *Einstellungen* → *Shop-Konfiguration* und der Gruppe *Sicherheit*. **Wie hängen Gruppen und Services zusammen?**
    Eine Gruppe ist die Kategorie, die der Besucher im Consent Layer (Cookie-Banner) sieht und per Checkbox akzeptieren oder ablehnen kann, z.B. "Marketing". Ein Service ist ein konkretes Tracking- oder Cookie-Tool, das dieser Gruppe zugeordnet ist, z.B. "Google Ads" oder "Meta Pixel". Einer Gruppe können beliebig viele Services zugeordnet werden. Der Besucher stimmt immer der gesamten Gruppe zu, nicht einzelnen Services. **Woher kommen die Service-Bezeichnungen?**
    Die Bezeichnungen unter `services` (z.B. `general.consentCookieService.googleads`) setzen sich immer aus dem Präfix `general.consentCookieService` und dem technischen Namen des jeweiligen Service zusammen. Es gibt folgende Arten von Services: * Mitgelieferte Standardservices - diese sind bereits im System vordefiniert und können direkt referenziert werden. Eine Liste der verfügbaren Standardservices befindet sich in Abschnitt 5.2. * Selbst angelegte Services - eigene Services können unter `general.consentCookieService` frei angelegt werden (z.B. für ein eigenes Tracking-Tool). Der dort vergebene `name` ergibt dann den Referenzpfad. #### Beispielkonfiguration für die Gruppe "Marketing" (`general.consentCookieGroup.marketing`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "description": "", "label": "", "name": "marketing", "services": [ "general.consentCookieService.awin", "general.consentCookieService.googleads", "general.consentCookieService.metapixel" ] } ``` Mehrere Services werden als Liste unter `services` eingetragen. Jeder Eintrag referenziert einen Service-Knoten, der unter `general.consentCookieService` angelegt wurde. #### Beispielkonfiguration für die Gruppe "Statistik" (`general.consentCookieGroup.statistics`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "description": "", "label": "", "name": "statistics", "services": [ "general.consentCookieService.googleanalytics", "general.consentCookieService.econda" ] } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `description` | string | Erklärtext zur Gruppe, der im Consent Layer für den Besucher angezeigt wird.
    Hier empfiehlt sich ein datenschutzrechtlich korrekter Hinweistext, z. B. mit Bezug auf Art. 6 DSGVO.

    | | `label` | string | Anzeigename der Gruppe im Consent Layer, z. B. „Marketing" oder „Statistik".

    | | `name` | string | Technischer Bezeichner der Gruppe.
    Wird intern für die Zuordnung und in der Template Engine verwendet.
    Nur Kleinbuchstaben, keine Sonderzeichen. | | `services` | multiAssoc | Liste der zugeordneten Services.
    Jeder Eintrag ist ein vollständiger Referenzpfad auf einen Knoten unter `general.consentCookieService`.
    Mehrere Services werden als Array eingetragen. | ### `general.consentCookieService` -Einzeldefinition zustimmungspflichtiger Cookies/Trackings Der Knoten `general.consentCookieService` enthält die Definitionen der einzelnen Dienste, die im Consent Layer (Cookie-Banner) angezeigt werden. Jeder Service steht für ein konkretes Tracking-, Analyse- oder Einbindungs-Tool, dem der Besucher explizit zustimmen oder widersprechen kann, z.B. Google Ads, Meta Pixel oder ein Captcha-Dienst. Jeder Service-Knoten beschreibt genau einen Dienst. Für jeden weiteren Dienst wird ein eigener Knoten angelegt. Die Services werden anschließend in Gruppen eingebunden. Wie das funktioniert, ist in Abschnitt 5.1 beschrieben. Die Einstellungen zu diesem Abschnitt befinden sich im Admin Interface unter *Einstellungen* → *Shop-Konfiguration* und der Gruppe *Sicherheit*. #### Beispielkonfiguration "Google Ads" (`general.consentCookieService.googleads`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "description": "", "label": "", "name": "googleads", "service": { "externalService": {}, "shopService": null } } ``` #### Beispielkonfiguration "Meta Pixel" (`general.consentCookieService.metapixel`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "description": "", "label": "", "name": "metapixel", "service": { "externalService": {}, "shopService": null } } ``` #### Beispielkonfiguration "Cookie-Warenkorb" (`general.consentCookieService.cookiebasket`) Für interne Shop-Funktionen, wie in diesem Beispiel, wird `shopService` gesetzt und `externalService` wird auf `null` gestellt. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "description": "", "label": "", "name": "cookiebasket", "service": { "externalService": null, "shopService": "CookieBasket" } } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ----------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `description` | string | Erklärungstext zum Dienst, der im Consent Layer für den Besucher angezeigt wird.
    Sollte verständlich beschreiben, wozu der Dienst genutzt wird.

    | | `label` | string | Anzeigename des Dienstes im Consent Layer, z. B. „Google Ads" oder „Meta Pixel".

    | | `name` | string | Technischer Bezeichner des Dienstes.
    Wird zur Zuordnung in Gruppen verwendet (als Teil des Referenzpfads `general.consentCookieService.`).
    Nur Kleinbuchstaben, keine Sonderzeichen. | | `service` | oneOf | Legt die Art des Dienstes fest. Genau einer der beiden Unterparameter wird gesetzt, der andere erhält `null`.
    Konfiguration für einen externen Dienst (Drittanbieter-Tools wie z.B. Google Ads): `"externalService": {}, "shopService": null`
    Konfiguration für einen internen Dienst (`"CookieBasket"`): `"externalService": null, "shopService": "CookieBasket"` | | `externalService` | object | Für alle externen Drittanbieter-Dienste.
    Wird als leeres Objekt `{}` angegeben – keine weitere Konfiguration erforderlich. | | `shopService` | enum | Für interne Shop-Funktionen.
    Verfügbarer Wert:
    `"CookieBasket"` (Cookie-Warenkorb).
    Für externe Dienste: `null`. | ## `general.country` - Länderdefinitionen Der Unterknoten `general.country` definiert alle Länder, die im Onlineshop zur Auswahl stehen - beispielsweise bei Rechnungsadresse, Lieferadresse oder in Formularen (z. B. Kontakt- oder Anfrageformularen). Konfiguration im Admin Interface unter *Einstellungen → Shop-Konfiguration → Gruppe „Adressdaten".* #### Beispielkonfiguration für Land "Deutschland" (`general.country.de`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "defaultTaxRate": "finance.taxRates.de", "isoAlpha2": "DE", "isoAlpha3": "DEU", "isoNum": "276", "name": "", "usedTaxes": "finance.taxRates.de" } ``` #### Beispielkonfiguration für Land "Polen" (`general.country.pl`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "defaultTaxRate": "finance.taxRates.pl", "isoAlpha2": "PL", "isoAlpha3": "POL", "isoNum": "616", "name": "", "usedTaxes": "finance.taxRates.pl" } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ---------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `active` | bool | Aktiviert (`true`) oder deaktiviert (`false`) das Land für die Auswahl in Adressformularen und Checkout-Prozessen. | | `isoAlpha2` | string | Zweistelliger ISO-Ländercode (nach ISO 3166-1 alpha-2), z. B. „DE" für Deutschland. | | `isoAlpha3` | string | Dreistelliger ISO-Ländercode (nach ISO 3166-1 alpha-3), z. B. „DEU" für Deutschland. | | `isoNum` | string | Numerischer ISO-Code (nach ISO 3166-1 numeric), z. B. „276" für Deutschland. | | `name` | string | Vollständiger Name des Landes, wie er im Shop bei der Länderauswahl angezeigt werden soll.

    | | `defaultTaxRate` | singleAssoc | Verknüpft das Land mit einem Standard-Steuersatz aus `finance.taxRates`.
    Dieser Steuersatz wird primär für die Steuerberechnung in diesem Lieferland verwendet. | | `usedTaxes` | singleAssoc | Angabe der zulässigen Steuersatz-Gruppe.
    Der Eintrag verweist auf Konfigurationen in `finance.taxRates` bzw. `finance.taxRatesAddition`.
    Wenn `defaultTaxRate` und `usedTaxes` nicht gesetzt sind, verwendet der Shop automatisch die globale Konfiguration aus `finance.taxes`. | Die offiziellen ISO-3166-1-Codes (alpha-2, alpha-3 und numerisch) finden sich auf der Website der International Organization for Standardization (ISO): [https://www.iso.org/iso-3166-country-codes.html](https://www.iso.org/iso-3166-country-codes.html) Um Länder ausschließen zu können, wird GeoIP von [IPLocate.io](http://IPLocate.io) eingesetzt. ## `general.customerAccountSettings` - Verhalten bei Löschung von Kundenkonten Der Unterknoten `general.customerAccountSettings` legt fest, wie das System mit Kundenkonten umgeht, wenn diese gelöscht werden sollen. Die Einstellung ist insbesondere relevant, wenn der Shop an eine Warenwirtschaft (WaWi) angebunden ist. Ist das Soft Delete aktiviert, wird ein vom Kunden gelöschtes Konto nicht sofort vollständig entfernt, sondern zunächst nur als „gelöscht" markiert. Der eigentliche Löschvorgang erfolgt erst, nachdem die WaWi den Kunden ebenfalls gelöscht hat. Auf diese Weise bleibt die Datenkonsistenz zwischen Shop und Warenwirtschaft gewährleistet. Wenn das Soft Delete deaktiviert ist (`softDelete = false`), erfolgt die Löschung sofort im Shop, bevor die WaWi darüber informiert wurde. Dadurch kann es zu Inkonsistenzen oder fehlenden Synchronisationen kommen. Konfiguration im Admin Interface unter *Einstellungen → Shop-Konfiguration → Gruppe „Kundenkonto"*. #### Beispielkonfiguration für alle Subshops (`general.customerAccountSettings`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "softDelete": false } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `softDelete` | bool | Legt fest, ob Kundenkonten beim Löschen lediglich deaktiviert (`true`) oder vollständig entfernt (`false`) werden.
    Diese Einstellung ist relevant, wenn eine Warenwirtschaft im Einsatz ist. | ## `general.deviceTypes` - Gerätetypen Der Knoten `general.deviceTypes` ist für die Definition und Verwaltung von Gerätetypen vorgesehen, die im Shop-System unterschieden oder gezielt angesprochen werden können (z. B. Desktop, Tablet, Smartphone). #### Beispielkonfiguration (`general.deviceTypes`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "deviceTypes": [ { "name": "mobile", "keywords": [ "iPhone", "Android Mobile", "Mobile", "Windows Phone", "Opera Mini" ] }, { "name": "tablet", "keywords": [ "iPad", "Android Tablet", "Tablet", "Kindle", "Silk" ] }, { "name": "desktop", "keywords": [ "Windows NT", "Mac OS X", "X11", "Linux x86_64", "Chrome Desktop" ] } ] } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------ | | `deviceTypes` | list (object) | Liste der Geräteklassen, die erkannt werden sollen.
    Jede Geräteklasse hat einen Namen und zugehörige Erkennungsmerkmale. | | `name` | enum | Bezeichnung der Geräteklassen:
    `mobile, tablet` oder `desktop` | | `keywords` | list (string) | Frei wählbare Schlüsselwörter zur Erkennung der Geräteklassen. (optional) | ## `general.garbageCollection` - Sitzungsverwaltung und automatische Aufräumprozesse Der Unterknoten `general.garbageCollection` definiert die Gültigkeitsdauer von Benutzersitzungen (Sessions) und legt fest, wann abgelaufene oder unvollständige Sessions automatisch gelöscht werden.
    Damit wird sichergestellt, dass veraltete Sitzungsdaten regelmäßig bereinigt werden und die Systemleistung stabil bleibt. Über diese Parameter lässt sich außerdem steuern, wie lange aktive und ausstehende (pending) Sessions bestehen bleiben dürfen, bevor sie aus dem System entfernt werden. Konfiguration im Admin Interface unter *Einstellungen → Shop-Konfiguration → Gruppe „Garbage Collection"*. #### Beispielkonfiguration für alle Subshop (`general.garbageCollection`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "pendingSessionAgeInHours": 72, "sessionAgeInMinutes": 120 } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | -------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `sessionAgeInMinutes` | int | Maximale Gültigkeitsdauer einer aktiven Session in Minuten.
    Nach Ablauf dieser Zeit wird die Sitzung automatisch beendet.
    Default: **120** | | `pendingSessionAgeInHours` | int | Maximale Lebensdauer einer unbestätigten oder inaktiven Session in Stunden (z. B. bei abgebrochenen Bestellvorgängen). Danach wird die Session beendet und es wird eine neue Session gestartet.
    Default: **72** | ## `general.general` - Allgemeine Basiseinstellungen Der Unterknoten `general.general` enthält zentrale Basisparameter, die das allgemeine Verhalten des Onlineshops steuern. Hier werden grundlegende technische Einstellungen wie der Aktivierungsstatus, erlaubte Parametergrenzen, die Zeitzone oder URL-Parameter zur Referer- und Subreferer-Erkennung festgelegt. Konfiguration im Admin Interface unter *Einstellungen → Shop-Konfiguration → Gruppe „Allgemein"*. #### Beispielkonfiguration für alle Subshop (`general.general`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "maxParamCount": 1000, "maxParamLength": 10000, "refererUrlParameter": "ref", "setRefererByUrl": true, "setSubrefererByUrl": true, "status": "active", "subrefererUrlParameter": "subref", "timeZone": "" } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `maxParamCount` | uint | Legt die maximale Anzahl an URL-Parametern fest, die der Shop in einer Anfrage verarbeitet.
    Diese Begrenzung dient dazu, die Systemlast zu kontrollieren und eine Überlastung durch sehr umfangreiche Anfragen zu vermeiden.
    Default: **1000** | | `maxParamLength` | uint | Maximale Zeichenlänge einzelner URL-Parameter.
    Default: **10000** | | `refererUrlParameter` | string | Definiert den URL-Parameter, über den ein Referer (z. B. Partner-Link) erkannt wird.
    Default: `ref`. | | `setRefererByUrl` | bool | Aktiviert (`true`) oder deaktiviert (`false`) die automatische Erkennung des Referers anhand des Parameters `refererUrlParameter`.
    Default: `true` | | `setSubrefererByUrl` | bool | Aktiviert (`true`) oder deaktiviert (`false`) die Erkennung des Subreferers über den Parameter `subrefererUrlParameter`.
    Default: `true` | | `status` | enum | Betriebsstatus des Shops.
    Steuert, ob und für wen ein Subshop öffentlich erreichbar ist.
    Die Konfiguration kann ebenfalls über Admin → Konfiguration → Subshops erfolgen.

    Mögliche Werte:
    - `active` (Shop ist live und für alle Besucher erreichbar)
    - `testmode` (Shop ist nur über den [Testmodus-Login](/konfiguration/general-allgemeine-shopeinstellungen#general-testmode-testmodus) erreichbar; als "Test" markierte Produkte werden sichtbar)
    - `inactive` (Jede Anfrage wird auf die Inaktiv-Seite umgeleitet) | | `subrefererUrlParameter` | bool | Definiert den URL-Parameter, über den ein Subreferer erkannt wird.
    Default: `subref`. | | `timeZone` | string | Definiert die Zeitzone des Shops (z. B. `Europe/Berlin`). | Beim setzen von `status` direkt über die Konfiguration (Admin-Interface oder API) findet keine Bereitschaftsprüfung statt. Der Wechsel auf `active` wird auch dann übernommen, wenn aktive Online-Zahlungsarten noch im Sandbox-Modus laufen.

    Für ein abgesichertes Live-Schalten verwenden Sie den Workflow unter *Admin → Konfiguration → Subshops* (Aktion "Live schalten") oder rufen Sie vorab den Endpoint `GET /shopStatus/goLive/{subshopId}` auf. Details siehe [hier](/frontend/funktionsubersicht/inaktiv-seite).
    ## `general.language` - Sprachdefinitionen Der Unterknoten `general.language` definiert alle Sprachen, die im System verfügbar sind. Diese Sprachen können anschließend in Subshops, Textbausteinen und sprachabhängigen Inhalten verwendet werden. Konfiguration im Admin Interface unter *Einstellungen → Shop-Konfiguration → Gruppe „Sprache"*. #### Beispielkonfiguration für die Sprache "Deutsch" (`general.language.de`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "isoCode": "DE", "name": "Deutsch" } ``` #### Beispielkonfiguration für die Sprache "Englisch" (`general.language.en`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "isoCode": "EN", "name": "English" } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------------------------------------------------------------------- | | `isoCode` | string | ISO-639-1-Code der Sprache (z. B. „DE" für Deutsch, „EN" für Englisch). | | `name` | string | Anzeigename der Sprache im Shop.
    Wird in Auswahllisten und Sprachumschaltern verwendet. | ## `general.numberFormat` - Zahlen- und Preisformatierung Der Unterknoten `general.numberFormat` definiert die Formatierung numerischer Werte im gesamten Shop. Über diese Einstellungen wird festgelegt, wie Preise, Gewichte, Mengen oder Bewertungen im Frontend dargestellt werden – z. B. mit welchem Dezimaltrennzeichen, wie viele Nachkommastellen angezeigt werden oder ob Tausendertrennzeichen genutzt werden. Diese Formatierungen wirken sich auf alle Ausgaben aus, die über die Template-Sprache *prepared format* erzeugt werden. Konfiguration im Admin Interface unter *Einstellungen → Shop-Konfiguration → Gruppe „Zahlenformatierung"*. #### Beispielkonfiguration für die Sprache "Deutsch" (`general.numberFormat.price`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "decimalPlaces": 2, "decimalSeparator": ",", "name": "price", "prefix": null, "suffix": null, "thousandsSeparator": null } ``` #### Beispielkonfiguration für die Sprache "Deutsch" (`general.numberFormat.weight`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "decimalPlaces": 2, "decimalSeparator": ",", "name": "weight", "prefix": null, "suffix": null, "thousandsSeparator": null } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | -------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `decimalPlaces` | uint | Anzahl der Nachkommastellen, die angezeigt werden sollen.
    Default: **2** | | `decimalSeparator` | string | Zeichen, das als Dezimaltrennzeichen verwendet wird (z. B. `,` oder `.`).
    Default: `"."` | | `name` | string | Interner Name des Formats (z. B. `price`, `amount`, `weight`). Dient der systemweiten Zuordnung. | | `prefix` | string | Zeichen oder Text, der vor dem Zahlenwert angezeigt wird (z. B. Währungssymbol, weil es bei manchen Währungen gängiger ist, das Währungssymbol vor dem Betrag zu setzen - Beispiel: £12 vs. 12€).
    Optional. | | `suffix` | string | Zeichen oder Text, der hinter dem Zahlenwert angezeigt wird (z. B. „kg" oder „€").
    Optional. | | `thousandsSeparator` | string | Zeichen für die Trennung von Tausenderstellen (z. B. `.` oder `,`). Kann `null` sein, wenn keine Trennung gewünscht ist.
    Optional. | ## `general.order` - Anzeige der Bestellhistorie Der Unterknoten `general.order` steuert die Darstellung und Sortierung der Bestellhistorie im Kundenkonto des Onlineshops. Hier wird festgelegt, wie Bestellungen gelistet, sortiert und paginiert werden, sowie welche Statuswerte dem Kunden angezeigt werden. So lassen sich Standard-Sortierungen, die Anzahl der Bestellungen pro Seite und die Anzeigeart der Bestellhistorie (z. B. subshopbezogen oder global) konfigurieren. Zudem können eigene Statusdefinitionen mit Symbolen und Beschriftungen für die Anzeige in der Storefront hinterlegt werden. #### Beispielkonfiguration für Status der Bestellungen (`general.order`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "defaultResultsPerPage": 20, "defaultSortOption": "general.orderSortOption.dateDesc", "maxResults": 1000, "orderHistoryDisplay": "currentSubShop", "resultsPerPageOptions": [ 5, 10, 20, 25, 30 ], "sortOptions": [ "general.orderSortOption.dateDesc", "general.orderSortOption.dateAsc" ], "states": [ { "id": 1, "caption": "In Bearbeitung", "icon": "clock", "action": "process" }, { "id": 2, "caption": "Versendet", "icon": "truck", "action": "ship" }, { "id": 3, "caption": "Storniert", "icon": "ban", "action": "cancel" } ] } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ----------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | `defaultResultsPerPage` | int | Legt fest, wie viele Bestellungen standardmäßig pro Seite angezeigt werden.
    Default: **20** | | `defaultSortOption` | singleAssoc | Bestimmt die voreingestellte Sortierung der Bestellliste (z. B. nach Datum absteigend).
    Optional. | | `maxResults` | int | Definiert die maximale Anzahl von Bestellungen, die gleichzeitig abgerufen oder angezeigt werden dürfen.
    Default: **1000** | | `orderHistoryDisplay` | enum | Legt fest, ob der Bestellverlauf für alle Subshops oder nur für den aktuell aktiven Subshop angezeigt wird (`allSubShops` / `currentSubShop`). | | `resultsPerPageOptions` | list (uint) | Enthält die auswählbaren Werte für die Anzahl der anzuzeigenden Bestellungen pro Seite.
    Default: `[20, 50, 100, 200]` | | `sortOptions` | multiAssoc | Liste der verfügbaren Sortieroptionen (z. B. nach Datum auf- oder absteigend).
    Verweise auf `general.orderSortOption.*`.
    Optional. | | `states` | list (object) | Liste der verfügbaren Bestellstatus (Array von Objekten). | | `id` | uint | Eindeutige numerische ID des Status (Unsigned Integer). Dient der technischen Referenz in Prozessen/Integrationen. | | `caption` | text | Anzeige- bzw. Klartextbezeichnung des Status (z. B. „Versendet"). | | `icon` | text | Symbolname für die UI-Darstellung (z. B. `truck`, `clock`). Konkrete Icon-Bibliothek abhängig vom Frontend. | | `action` | text | Technisches Aktionskürzel, das z. B. Workflows oder Buttons triggert (z. B. `ship`, `cancel`). | ## `general.orderSortOption` - Sortierung der Bestellhistorie Legt individuelle Sortieroptionen für die Bestellübersicht fest. Etwa nach Datum, Gesamtbetrag oder Status. Jede Option erhält einen frei wählbaren, eindeutigen Namen und verweist auf ein in der Bestellliste verfügbares Feld. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "date_desc", "fieldName": "dateCreated", "direction": "desc" } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string (unique) | Eindeutige Benamung der Sortieroption.
    Kann frei gewählt werden. | | `fieldName` | string | Datenfeld, nach dem sortiert wird. (z.B. `dateCreated`, `totalPrice`, `status`).
    Muss ein in der Bestellliste verfügbares Sortierfeld sein. | | `direction` | enum | Gibt die Sortierrichtung vor.
    `asc` = aufsteigend, `desc` = absteigend. | ## `general.productRating` - Produktbewertung Der Knoten `general.productRating` steuert das Bewertungs­system für Produkte im Shop.
    Hier werden die Rahmenbedingungen für Produktbewertungen (Bewertungsskala, Pflichtfelder, Textlängen, Mehrfachbewertungen) sowie die Einstellungen für automatische Bewertungs-Erinnerungen per E-Mail definiert. #### Beispielkonfiguration (`general.productRating`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "maximumRating": 5, "minimumRating": 1, "allowRatingAfterEachOrder": false, "ratingFields": { "descriptionMaxLength": 1000, "descriptionRequired": true, "pointsRequired": true, "subjectMaxLength": 100, "subjectRequired": true }, "reminderEmail": { "active": true, "consentRequired": true, "consentService": "ratereminder", "intervalInDays": 1, "templateEmail": { "senderAddress": "noreply@websale.de", "subject": "Bewerten Sie die von Ihnen bestellten Produkte!", "template": "rateReminder.htm" } } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `maximumRating` | int | Höchstwert der Bewertungsskala (z. B. 5 für ein 5-Sterne-System).
    Default: **5** | | `minimumRating` | int | Niedrigster Bewertungswert.
    Default: **1** | | `allowRatingAfterEachOrder` | bool | Erlaubt Mehrfachbewertungen desselben Produkts durch denselben Benutzer
    (`true` = Mehrfachbewertungen erlaubt, `false` = nicht erlaubt / default). | | `ratingFields` | object | Objekt mit Vorgaben für die Eingabefelder im Bewertungsformular. | | `descriptionMaxLength` | int | Maximale Zeichenanzahl für den Freitext der Bewertung.
    Default: **1000** | | `descriptionRequired` | bool | Gibt an, ob das Beschreibungsfeld ein Pflichtfeld ist (`true`/`false`).
    Default: `true` | | `pointsRequired` | bool | Legt fest, ob die Angabe einer Punktebewertung verpflichtend ist (`true`/`false`).
    Default: `true` | | `subjectMaxLength` | int | Maximale Zeichenanzahl für den Betreff/Titel einer Bewertung.
    Default: **100** | | `subjectRequired` | bool | Gibt an, ob der Betreff/Titel verpflichtend ist (`true`/`false`).
    Default: `true` | | `reminderEmail` | object | Objekt mit Einstellungen für die automatische Bewertungs-Erinnerungs-E-Mail. | | `active` | bool | Aktiviert (`true`) oder deaktiviert (`false`) den automatischen Versand von Bewertungs-Erinnerungen.
    Default: `false` | | `consentRequired` | bool | Legt fest, ob eine Einwilligung des Kunden für die Bewertungs-Erinnerung erforderlich ist. | | `consentService` | string | Name des zugehörigen Consent-Dienstes, über den die Zustimmung verwaltet wird (z. B. `ratereminder`). | | `intervalInDays` | int | Zeitabstand (in Tagen) zwischen Bestellung und Versand der Bewertungs-Erinnerung.
    Default: **14** | | `templateEmail` | object | E-Mail-Template für den Versand der Bewertungs-Erinnerung. | | `senderAddress` | string | Absender-E-Mailadresse der Bewertungs-Erinnerung. | | `subject` | string | Betreffzeile der E-Mail. | | `template` | string | Dateiname des verwendeten E-Mail-Templates (z. B. `rateReminder.htm`). | ## `general.salutation` - Anreden Der Unterknoten `general.salutation` definiert alle verfügbaren Anreden, die im Shop angezeigt werden – etwa in Adressformularen, Registrierungen oder Kontaktformularen. Jede Anrede besteht aus einem technischen Code und einem anzuzeigenden Text.
    Die Reihenfolge der Einträge entspricht der Anzeige im Frontend. Konfiguration im Admin Interface unter *Einstellungen → Shop-Konfiguration → Gruppe „Adressdaten"*. #### Beispielkonfiguration (`general.salutation`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "codeList": [ { "code": "1", "text": "Herr" }, { "code": "2", "text": "Frau" }, { "code": "3", "text": "Familie" }, { "code": "4", "text": "Firma" } ] } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------------- | ------------------------------------------------------------------------------------------------------------- | | `codeList` | list (object) | Liste aller verfügbaren Anreden.
    Jeder Eintrag enthält einen technischen Code und den angezeigten Text. | | `code` | string | Technischer Code der Anrede.
    Wird systemintern zur Identifikation verwendet. | | `text` | string | Anzeigetext der Anrede im Frontend (z. B. „Herr", „Frau"). | ## `general.sitemap` - Aktivierung von Sitemap Der Unterknoten `general.sitemap` steuert den Basispfad der Sitemap. Über diesen Parameter kann konfiguriert werden, wo sich der Basispfad bzw. der Oberknoten befindet, unterhalb dessen die Sitemaps abgelegt werden. Die Konfiguration erfolgt im Admin-Interface unter SEO. #### Beispielkonfiguration (`general.sitemap`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "baseDirectory": "sitemap" } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | --------------- | ------- | ------------------------------------------------------------------------------------------------------------- | | `baseDirectory` | string | Legt fest, wo sich der Basispfad bzw. der Oberknoten befindet, unterhalb dessen die Sitemaps abgelegt werden. | ## `general.subshop` - Subshop-Definitionen Der Unterknoten `general.subshop` definiert die einzelnen Subshops innerhalb der Plattform. Jeder Subshop-Eintrag enthält eine eindeutige ID, eine optionale Sprachzuordnung und eine technische Speicherreferenz. Konfiguration im Admin Interface unter *Einstellungen → Shop-Konfiguration → Gruppe „Subshops"*. #### Beispielkonfiguration für den Subshop "deutsch" (`general.subshop.deutsch`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "dataSubshop": null, "language": "general.language.de", "storageId": "" } ``` #### Beispielkonfiguration für den Subshop "english" (`general.subshop.englisch`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "dataSubshop": null, "language": "general.language.en", "storageId": "" } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string (`unique, readonly`) | Systemname des Subshops.
    Wird automatisch vergeben und kann nicht verändert werden. | | `dataSubshop` | singleAssoc | Referenz auf den zugehörigen Daten-Subshop (z.B. DE-Shop).
    Bestimmt, aus welchem Subshop-Kontext Daten gelesen / geschrieben werden.
    target: `general.subshop` | | `language` | singleAssoc | Verknüpft den Subshop mit einer Sprache (z.B. `general.language.en`).
    target: `general.language` | | `storageId` | string | Interne Speicher-ID, unter der die Daten des Subshops abgelegt werden.
    Wird systemseitig für Datentrennung und Indexierung genutzt. | ## `general.subshopView` - Subshop-Konfigurationen Der Unterknoten `general.subshopView` definiert die Basis-Einstellungen für jeden einzelnen Subshop. Hier werden unter anderem Sprache, Währung, Länderzuordnung, das verwendete Theme und der Standard-Produkttyp des jeweiligen Subshops festgelegt. Diese Konfiguration bestimmt, wie der Subshop im Frontend angezeigt wird und welche Rahmenbedingungen (z. B. gültige Länder, Sprache, Preisformatierung) gelten. Sie baut auf den Subshop-Definitionen aus `general.subshop` auf. Konfiguration im Admin Interface unter *Einstellungen → Shop-Konfiguration → Gruppe „Subshops"*. #### Beispielkonfiguration für den Subshop "deutsch" (`general.subshopView.deutsch`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "countries": [ "general.country.de", "general.country.at", "general.country.ch", "general.country.be", "general.country.it", "general.country.pl", "general.country.nl" ], "currency": "finance.currency.euro", "defaultProductType": "content.productType.standard", "language": "general.language.de", "theme": "default" } ``` #### Beispielkonfiguration für den Subshop "englisch" (`general.subshopView.english`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "countries": [ "general.country.us", "general.country.gb", "general.country.au", "general.country.ca" ], "currency": "finance.currency.dollar", "defaultProductType": "content.productType.standard", "language": "general.language.en", "theme": "default" } ``` #### Parameterbeschreibung | **Parameter** | | **Beschreibung** | | -------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `countries` | multiAssoc | Liste der Länder, die im jeweiligen Subshop zur Auswahl stehen (z. B. für Liefer- und Rechnungsadressen).
    Verweist auf Einträge unter `general.country`. | | `currency` | singleAssoc | Verknüpfte Währung des Subshops.
    Verweist auf Einträge unter `finance.currency.[name]`. | | `defaultProductType` | singleAssoc | Standard-Produkttyp, der für die Darstellung und Verarbeitung von Artikeln verwendet wird (z. B. `content.productType.standard`). | | `language` | singleAssoc | Definiert die Sprache des Subshops.
    Verweist auf Einträge unter `general.language.[name]`. | | `theme` | string | Bezeichnet den im Subshop verwendeten Templatesatz.
    Default: `default` | ## `general.testMode` - Testmodus Der Unterknoten `general.testMode` aktiviert und steuert den Testmodus des Shops. Der Testmodus wird über eine spezielle Shop-URL mit Parametern aufgerufen. Beim Aufruf erscheint eine Eingabemaske, über die ein vordefiniertes Passwort eingegeben werden muss, um den Zugang freizuschalten. Erst nach erfolgreicher Authentifizierung ist der Shop über die URL nutzbar. Diese Funktion dient dazu, Änderungen, neue Inhalte oder Layout-Anpassungen zu prüfen, ohne dass reguläre Besucher Zugriff haben. Der Testmodus (inklusive `basicAuthActive` / `basicAuthUsers`) schützt ausschließlich die **Testumgebung** vor regulären Besuchern. Um einen **Live-Shop** auf angemeldete Kunden zu beschränken (z. B. geschlossener B2B-Shop), verwenden Sie stattdessen die [B2B-Zutrittsbeschränkung](/konfiguration/b2b-business-to-business-b2b). Konfiguration im Admin Interface unter *Einstellungen → Shop-Konfiguration → Gruppe „Testmodus"*. #### Beispielkonfiguration für alle Subshops (`general.testMode`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "allowedUserAgents": null, "basicAuthActive": false, "basicAuthUsers": null, "password": "test", "template": "testMode.htm", "userAgentBypassActive": false } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ----------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `allowedUserAgents` | list (string) | Liste von User-Agents (z. B. Browser, Testsysteme), die den Testmodus ohne Passworteingabe betreten dürfen. | | `basicAuthActive` | bool | Aktiviert (`true`) oder deaktiviert (`false`) eine zusätzliche HTTP-Basic-Authentifizierung. | | `basicAuthUsers` | list (object) | Liste der Benutzer mit Berechtigung für den Zugang per HTTP-Basic-Auth.
    Nur relevant, wenn `basicAuthActive = true`. | | `username` | string | Benutzername des HTTP-Basic-Auth Users. | | `password` | string | Passwort des HTTP-Basic-Auth Users. | | `password` | string | Passwort, das beim Aufruf der Testmodus-URL eingegeben werden muss, um den Shop freizuschalten. | | `template` | string | Template-Datei für die Passwortabfrage (z. B. `testMode.htm`). | | `userAgentBypassActive` | bool | Aktiviert (`true`) oder deaktiviert (`false`), ob bestimmte User-Agents den Testmodus ohne Passwort umgehen dürfen (abhängig von `allowedUserAgents`). | ## `general.title` - Titel für die Anrede Der Unterknoten `general.title` definiert alle verfügbaren **Titel**, die im Shop zur Auswahl stehen – beispielsweise in Adressformularen, Registrierungen oder Kontaktformularen. Jeder Eintrag besteht aus einem technischen Code und dem anzuzeigenden Titeltext (z. B. *Dr.*, *Prof.*). Diese Werte werden im Frontend in der Titel-Auswahlliste angezeigt und können bei Bedarf erweitert oder angepasst werden. Konfiguration im Admin Interface unter *Einstellungen → Shop-Konfiguration → Gruppe „Adressdaten"*. #### Beispielkonfiguration für alle Subshops (`general.title`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "codeList": [ { "code": "1", "text": "" }, { "code": "2", "text": "Dr." }, { "code": "3", "text": "Prof." } ] } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------------- | ----------------------------------------------------------------------------------------------------------- | | `codeList` | list (object) | Liste aller verfügbaren Titel. Jeder Eintrag besteht aus einem technischen Code und dem dazugehörigen Text. | | `code` | string | Technischer Code des Titels. Wird systemintern zur Identifikation verwendet. | | `text` | string | Anzeigetext des Titels im Frontend (z. B. „Dr." oder „Prof."). | ## `general.zipCodes` - Postleitzahl-Prüfungen Der Unterknoten `general.zipCodes` definiert die **syntaktische Prüfung von Postleitzahlen** für einzelne Länder. Für jedes Land kann ein regulärer Ausdruck (Regex) hinterlegt werden, mit dem überprüft wird, ob eine eingegebene Postleitzahl dem landesspezifischen Format entspricht. Diese Validierung erfolgt beispielsweise in Formularen oder im Checkout-Prozess, um fehlerhafte Eingaben zu vermeiden. Konfiguration im Admin Interface unter *Einstellungen → Shop-Konfiguration → Gruppe „Adressdaten"*. #### Beispielkonfiguration für alle Subshops (`general.zipCodes`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "zipCodes": [ { "country": "general.country.de", "zipRegex": "^[0-9]{5}$" }, { "country": "general.country.at", "zipRegex": "^[0-9]{4}$" }, { "country": "general.country.ch", "zipRegex": "^[0-9]{4}$" } ] } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `zipCodes` | list (object) | Liste aller Postleitzahlregeln. Jeder Eintrag definiert ein Land und den zugehörigen Prüf-Regex. | | `country` | singleAssoc | Verweis auf das Land, für das die Regel gilt (z. B. `general.country.de`). | | `zipRegex` | string | Regulärer Ausdruck, der das gültige Postleitzahlformat des jeweiligen Landes beschreibt (z. B. `^[0-9]{5}$` für Deutschland). | # inquiry - Formulare Source: https://dokumentation.websale.de/konfiguration/inquiry-formulare Der inquiry-Knoten steuert shopseitige Formulare im WEBSALE: Kontakt-, Widerrufs-, Retouren- und Katalogbestellformulare je als eigener Konfigurationsknoten. Der Knoten `inquiry` steuert shopseitige Formulare (z. B. Kontakt, Widerruf, Retoure, Katalogbestellung). Die Konfiguration von Formularen erfolgt im Admin Interface unter dem Service *Anfragen*. In der Konfigurationsübersicht werden die Formulare nicht angeboten. Die übrigen Knoten des Bereichs, beispielsweise `inquiry.ruleSet`, bleiben dort unverändert erreichbar. Jedes Formular wird als eigener Unternode unter `inquiry.form.` definiert. ## `inquiry*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `inquiry`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "inquiry": { "form": { "catalogue": { ... }, "contact": { ... }, "productQuestion": { ... }, "returnInquiry": { ... } }, "fieldPreset": { ... }, "ruleSet": { ... } } } ``` #### Parameterbeschreibung | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `form` | Container für alle Formular-Definitionen unterhalb von `inquiry`.
    Die direkten Keys innerhalb von `form` sind die technischen Formularnamen. | | `` | Platzhalter für einen konkreten Formular-Knoten (z. B. `catalogue`, `contact`, `productQuestion`, `returnInquiry`).
    Das zugehörige Objekt enthält die vollständige Konfiguration dieses Formulars (z. B. Felder, Validierungen, E-Mail-Einstellungen). | | `fieldPreset` | Container für globale, wiederverwendbare Felddefinitionen. | | `ruleSet` | Container für regelbasierte Feldsteuerungen, die Formularen zugewiesen werden können. | ## `inquiry.form` - Formular-Konfiguration Jedes Formular unterhalb von `inquiry.form` enthält die vollständige Konfiguration für ein bestimmtes Anfrageformular (z. B. Kontakt, Kataloganforderung, Produktfrage, Retoure). Hier werden die Formularfelder, Validierungen, optionale Captcha-Prüfungen sowie die E-Mail-Parameter definiert, über die die Anfrage weitergeleitet oder bestätigt wird. #### Beispielkonfiguration für ein Kontaktformular (`inquiry.form.contact`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "captcha": { "service": "captchaCheck.recaptchav3" }, "fieldPresets": null, "fields": [ { "label": "", "name": "subject", "required": true, "validations": [ { "options": { "len": 1 }, "service": "dataChecker.minLength" }, { "options": { "len": 200 }, "service": "dataChecker.maxLength" } ] }, { "label": "", "name": "comment", "required": true, "validations": [ { "options": { "len": 1 }, "service": "dataChecker.minLength" }, { "options": { "len": 10000 }, "service": "dataChecker.maxLength" } ] } ], "inquiryEmail": { "fromAddress": "noreply@websale.de", "fromName": "Mustershop", "merchantEmail": "noreply@websale.de", "subject": "Ihre Kontaktanfrage", "template": "contact.htm" }, "name": "contact", "ruleSet": "inquiry.ruleSet.contactRules" } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | --------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | Technischer Name des Formulars. Ist frei wählbar, muss aber eindeutig sein. | | `fieldPresets` | multiAssoc | Verweist auf vordefinierte Feldgruppen (globale Formularfelder), die zentral unter `inquiry.fieldPreset` definiert sind.
    Dadurch können gemeinsam genutzte Felder (z. B. Name, E-Mail-Adresse) in mehreren Formularen wiederverwendet werden.
    Die Zuweisung erfolgt über eine Liste von Referenzen auf die jeweiligen Preset-Knoten, z. B.: `"fieldPresets": [ "inquiry.fieldPreset.firstName", "inquiry.fieldPreset.lastName" ]`
    Wenn keine globalen Feldvorgaben verwendet werden sollen, ist der Wert `null` zu setzen. | | `fields` | list (object) | Liste der Eingabefelder, die im Formular abgefragt werden sollen | | `name` | string | Technischer Feldname (Key). | | `label` | string | Anzeigename im Formular.

    | | `required` | bool | Pflichtfeldkennzeichen (`true`/`false`).
    Default: `false` | | `validations` | multiService | Liste von Validierungsregeln für das Feld. Optional.
    target: `InputValidation` | | `service` | -- | Validierungsdienst, z. B. `dataChecker.minLength`, `dataChecker.maxLength`.
    Jeder Eintrag verweist auf einen Knoten unter `dataChecker`
    Übersicht der verfügbaren Validierungs- und Prüfregeln für Formularfelder finden Sie [hier](/konfiguration/validierungs-und-prufservices). | | `options` | -- | Optionsobjekt zur Regelkonfiguration, z. B. `{ "len": 200 }`. | | `captcha` | singleService | Objekt für die Captcha-Konfiguration (Spam-/Bot-Schutz). Optional. | | `service` | -- | Enthält den Service-Namen, z. B. `captchaCheck.recaptchav3`.
    Jeder Eintrag verweist auf einen Knoten unter `captcha`. | | `inquiryEmail` | object | Objekt für den E-Mail-Versand der Anfrage. | | `fromAddress` | string | Absender-E-Mailadresse. | | `fromName` | string | Absender-Anzeigename. | | `merchantEmail` | string | Optionale Kopie an eine interne Händler-/Service-Adresse. Der Hauptempfänger der Eingangsbestätigung ist immer der Anfragende – die Empfängeradresse wird nicht hier konfiguriert, sondern dynamisch aus dem HTML-Formularfeld `` übernommen (Pflichtparameter der [`InquirySend`-Aktion](/frontend/referenz/aktionen/inquiry)). | | `subject` | string | Betreffzeile der ausgehenden Nachricht. | | `template` | string | Name der HTML-Datei für das E-Mail-Template, z. B. `contact.htm`.
    Der Wert wird relativ zum Verzeichnis `mails/` des Template-Themes aufgelöst - das System stellt `mails/` automatisch voran.
    `mails/` darf daher nicht mit angegeben werden (richtig: `contact02.htm`, falsch: `mails/contact02.htm`).
    Mehr dazu unter [E-Mails & E-Mail Einstellungen](/konfiguration/e-mails-e-mail-einstellungen). | **Empfängeradresse und BCC** Die Bestätigungsmail an den Kunden geht immer an die Adresse, die im HTML-Formular über das Feld `` übermittelt wird. Fehlt dieses Feld im Frontend-Template, wird keine Eingangsbestätigung versendet – unabhängig davon, welche Felder unter `fields` konfiguriert sind. Das Feld `email` ist ein separater Aktionsparameter (siehe [`InquirySend`](/frontend/referenz/aktionen/inquiry)) und muss nicht zusätzlich unter `fields` deklariert werden. Ein `bcc`- oder `cc`-Parameter wird von `inquiryEmail` nicht unterstützt. Für eine zusätzliche interne Kopie steht ausschließlich `merchantEmail` zur Verfügung. \| `ruleSet` | string | Verweis auf ein `ruleSet` unter `inquiry.ruleSet`, z.B. "`inquiry.ruleSet.contactRules`".
    Ermöglicht die regelbasierte Steuerung von Feldattributen wie Sichtbarkeit, Pflichtfeld-Status, Labels und Standardwerten. | ## `inquiry.fieldPreset` - Globale Felddefinitionen Der Knoten `inquiry.fieldPreset` dient zur zentralen Definition von wiederverwendbaren Formularfeldern. Über diese globalen Feldvorgaben können standardisierte Felder (z. B. Vorname, Nachname, E-Mail-Adresse, Telefonnummer) einmalig definiert und anschließend in mehreren Formularen eingebunden werden. Ein einzelner Preset-Knoten unterhalb von `inquiry.fieldPreset` enthält die vollständige Felddefinition analog zu den Feldobjekten innerhalb der jeweiligen Formular-Konfiguration (`inquiry.form..fields`). Die Einbindung erfolgt über den Parameter `fieldPresets` im entsprechenden Formular, indem auf die Preset-Namen verwiesen wird. #### Beispielkonfiguration für alle `inquiry.fieldPreset` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "firstName": { "label": "", "name": "firstName", "required": true, "validations": [ { "service": "dataChecker.minLength", "options": { "len": 1 } }, { "service": "dataChecker.maxLength", "options": { "len": 50 } } ] }, "lastName": { "label": "", "name": "lastName", "required": true, "validations": [ { "service": "dataChecker.minLength", "options": { "len": 1 } }, { "service": "dataChecker.maxLength", "options": { "len": 50 } } ] } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `label` | string | Anzeigename des Feldes im Formular.

    | | `name` | string | Technischer Feldname (Key) – wird für Datenübergabe und E-Mail-Ausgabe verwendet. | | `required` | bool | Pflichtfeldkennzeichen (`true`/`false`).
    Default: `false` | | `validations` | multiService | Liste der Validierungsregeln für das Feld.
    Optional. | | `service` | -- | Name des Validierungsdienstes, z. B. `dataChecker.minLength`, `dataChecker.maxLength`.
    Übersicht der verfügbaren Validierungs- und Prüfregeln für Formularfelder finden Sie [hier](/konfiguration/validierungs-und-prufservices). | | `options` | -- | Parameterobjekt zur Definition der Regel, z. B. `{ "len": 50 }`. | ## `inquiry.ruleSet` - Regelbasierte Feldsteuerung Der Knoten `inquiry.ruleSet` ermöglicht die dynamische, regelbasierte Steuerung von Formularfeldern. Über `RuleSets` können Feldattribute wie Sichtbarkeit, Pflichtfeld-Status, Labels und Standardwerte abhängig von Bedingungen (z.B. dem aktuellen Wert eines anderen Feldes) zur Laufzeit angepasst werden. Ein `RuleSet` wird über `inquiry.ruleSet.` definiert und über den Parameter `ruleSet` im jeweiligen Formular (`inquiry.form.`) eingebunden. #### Beispielkonfiguration für `inquiry.ruleSet.contactRules` ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} customLabelsDefinition: - conditions: - field: subject type: value value: Anruf fields: - text label: defaultValuesDefinition: - conditions: - field: lastName type: value value: Musterfrau fields: - firstName value: Maria - conditions: null fields: - text value: |- Sehr geehrtes Myshop-Team, Ich interessiere mich brennend für euer Produktsortiment. Bitte tretet mit mir in Kontakt. Viele Grüße, inputVisibilityDefinition: - conditions: - field: subject type: inlist valueList: - Anruf fields: - customerNumber visible: false resetIfHidden: false requiredDefinition: - conditions: - field: lastName type: notvalue value: Musterfrau fields: - firstName value: true ``` #### Parameterübersicht für die Allgemeine Regelstruktur | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `conditions` | list (object) | Liste von Bedingungen, die alle erfüllt sein müssen, damit die Regel greift. Bei `null` greift die Regel immer. | | `field` | string | Technischer Name des Feldes, dessen Wert geprüft wird. | | `type` | string | Art der Prüfung.
    Verfügbare Typen:
    - `value` - exakter Vergleichswert
    - `notvalue` - Wert stimmt nicht überein
    - `inlist` - Wert ist in einer Liste enthalten | | `value` | string | Vergleichswert (bei `type`= `value` oder `notvalue`). | | `valueList` | list (string) | Liste von Vergleichswerten (nur `type` = `inlist`). | | `fields` | list (string) | Liste der technischen Feldnamen, auf die die Regel angewendet wird. | #### Zusätzliche Parameter je Definition `customLabelsDefinition` | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------ | | `label` | string | Das neue Label, das die betroffenen Felder erhalten, wenn die Bedingungen zutreffen.

    | `defaultValuesDefinition` | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | -------------------------------------------------------------- | | `value` | string | Der Standardwert, der für die betroffenen Felder gesetzt wird. | `inputVisibilityDefinition` | **Parameter** | **Typ** | **Beschreibung** | | --------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------- | | `visible` | bool | Gibt an, ob die betroffenen Felder sichtbar (`true`) oder ausgeblendet (`false`) sein sollen. | | `resetIfHidden` | bool | Gibt an, ob der Feldwert beim Ausblenden zurückgesetzt wird (`true`) oder erhalten bleibt (`false`).
    Default: `false` | `requiredDefinition` | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ---------------------------------------------------------------------------------------------------------------- | | `value` | bool | Gibt an, ob die betroffenen Felder als Pflichtfeld (`true`) oder als optionales Feld (`false`) behandelt werden. | # maintenance - Wartungsmodus Source: https://dokumentation.websale.de/konfiguration/maintenance-wartungsmodus Konfiguration des Wartungsmodus über den maintenance-Knoten: Shop temporär sperren, Zugriff verhindern und individuelle Wartungsmeldung im Frontend anzeigen. Der Wartungsmodus steuert, ob der Shop vorübergehend für Kunden gesperrt wird - z.B. für größere Updates oder Deployments.\ Ist der Modus aktiv, kann auf den Shop nicht von außen zugegriffen werden.\ Zusätzlich kann eine Wartungsmeldung hinterlegt werden, die im Frontend angezeigt wird. *** ## `maintenance*` - Grundaufbau Nachfolgend der Grundaufbau des Knotens `maintenance`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorCodes": { "maintenanceModeActive": "Der Shop wird gerade gewartet. Bitte später erneut versuchen." } } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ----------------------- | ------- | --------------------------------------------------------------- | | `errorCodes` | -- | Hauptknoten. | | `maintenanceModeActive` | string | Meldung, die ausgegeben wird, wenn der Wartungsmodus aktiv ist. | # messages - Ereignisgesteuerte E-Mails Source: https://dokumentation.websale.de/konfiguration/messages-ereignisgesteuerte-e-mails Der messages-Knoten konfiguriert ereignisgesteuerte, benutzerdefinierte E-Mails an Shop-Verantwortliche, Lieferanten oder Hersteller via Template-Trigger. Der Knoten `messages` dient zur Konfiguration benutzerdefinierter E-Mail-Benachrichtigungen, die automatisch ausgelöst werden, sobald im Shop bestimmte Ereignisse oder Zustände eintreten. Neben den standardmäßig versendeten System-E-Mails (z. B. Bestellbestätigung, Versandinformation oder Lagerbestandswarnung) können hier individuelle E-Mails definiert werden, die gezielt an bestimmte Empfängergruppen gesendet werden – etwa an Shop-Verantwortliche, Lieferanten oder Hersteller. **Wichtig:** Nicht die E-Mail selbst wird im Template integriert, sondern der Trigger für ihren Versand. Im Template wird per Template-Engine die Bedingung geprüft (z. B. „keine Suchergebnisse gefunden"). Wenn diese erfüllt ist, wird die passende Nachricht über ihre ID (z. B. `order_confirmation`) zum Versand angestoßen. Diese Funktion ermöglicht es, auch shopindividuelle Ereignisse abzubilden, die für den Betrieb oder die Logistik eines bestimmten Shops relevant sind. Neue E-Mails können aktuell nur über die [REST API Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) erstellt werden. *** ## `messages*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `messages` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "messages": { "emails": {...} } } ``` #### Parameterbeschreibung | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------- | | `emails` | Konfiguriert System-E-Mails für den Shop. | *** ## `messages.emails` - Ereignisgesteuerte E-Mails Konfiguriert System-E-Mails für den Shop. Jede Konfiguration ist über eine eindeutige ID adressierbar und das Template kann je Subshop unterschiedlich gepflegt werden. #### Beispielkonfiguration `messages.emails.additionalMail` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "order_confirmation", "sender": "shop@example.com", "subject": "Bestellbestätigung", "recipient": "customer@example.com", "template": "order_confirmation.htm" } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | `string` | Eindeutige Kennung der E-Mail-Konfiguration (z.B. `order_confirmation`).
    Frei wählbar.
    Die ID wird vom Template verwendet, um die zugehörige Konfiguration zu finden. | | `recipient` | `string` | Empfängeradresse der E-Mail. | | `sender` | `string` | Absenderadresse der E-Mail. | | `subject` | `string` | Betreffzeile der E-Mail. | | `template` | `string` | Pfad / Name der zu verwendenden E-Mail-Vorlage. (z.B. `order_confirmation.htm`) | # newsletter - Newsletter Source: https://dokumentation.websale.de/konfiguration/newsletter-newsletter Der newsletter-Knoten bündelt An- und Abmeldung, Double-Opt-In-Bestätigungen sowie die Konfiguration der zugehörigen E-Mail-Formulare und Inhalte. Der Knoten `newsletter` bündelt alles rund um Newsletter An- und Abmeldung sowie die dazugehörigen E-Mails. Hier kann beispielsweise festgelegt werden, ob eine Bestätigung (Double-Opt-In) für verschiedene Aktionen nötig ist und wie die E-Mail-Formulare dargestellt werden und was sie beinhalten sollen. *** ## `newsletter*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `newsletter` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "newsletter": { "field": { }, "newsletter": { } } } ``` #### Parameterbeschreibung | **Parameter** | **Beschreibung** | | ------------- | --------------------------------------------------------- | | `field` | Definiert ein einzelnes Feld für das Newsletter-Formular. | | `newsletter` | Definiert grundlegende Newsletter-Funktionen. | *** ## `newsletter.field` - Formularfeld für Newsletter Der Knoten `newsletter.field` definiert ein einzelnes Feld des Newsletter-Formulars. Man legt damit beispielsweise die Bezeichnung, den Feldtyp sowie Validierungen fest. Das Frontend rendert die Eingabe entsprechend dieser Vorgaben. #### Beispielkonfiguration (Feld "Vorname" hinzufügen) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "newsletter": { "fields": { "firstName": { "name": "firstName", "label": "", "required": false, "type": "text", "validations": [ { "service": "formCheck.minlen", "options": { "len": 3 } }, { "service": "formCheck.maxlen", "options": { "len": 50 } } ] } } } } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `name` | string | Technischer Name des Formularfeldes.
    Muss eindeutig sein und ist selbst wählbar.
    Wird beim Absenden des Formulars sowie beim Import / Export verwendet. | | `label` | string | Anzeigename im [Admin-Interface](/admin-interface).

    | | `required` | bool | Markiert das Feld als Pflichtfeld.
    Default: `true` | | `type` | enum | Gibt den Feldtyp an.
    Mögliche Werte:
    - `text` - Freitextfeld
    - `salutation` - Auswahl einer im Shop konfigurierten [Anrede](/konfiguration/general-allgemeine-shopeinstellungen#general-salutation-anreden)
    - `title` - Auswahl eines im Shop konfigurierten [Titels](/konfiguration/general-allgemeine-shopeinstellungen#general-title-titel-für-die-anrede) | | `validations` | multiService | Liste von Validierungsregeln zur Prüfung des Feldinhalts.
    Wird nur bei Freitextfeldern (`type: text` ) unterstützt.
    Mehr unter [Validierungs- und Prüfservices](/konfiguration/validierungs-und-prufservices)
    Target: `inputValidation` | *** ## `newsletter.newsletter` - Newsletter Einstellungen Der Knoten `newsletter.newsletter` steuert alle grundlegenden Newsletter-Funktionen, zum Beispiel Double-Opt-In und An-/Abmeldung. Es können Templates, Betreffzeilen, Absenderangaben uvm. bestimmt werden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "blacklistSelfDoubleOptIn": true, "doubleOptInEmailBlacklist": { "fromAddress": "no-reply@websale.de", "fromName": "WEBSALE", "subject": "Bestätigen Sie Ihre Blacklist Anmeldung", "template": "newsletterBlacklist.htm" }, "doubleOptInEmailSubscribe": { "fromAddress": "no-reply@websale.de", "fromName": "WEBSALE", "subject": "Bestätigen Sie Ihre Registrierung", "template": "newsletterSubscribe.htm" }, "doubleOptInEmailUnsubscribe": { "fromAddress": "no-reply@websale.de", "fromName": "WEBSALE", "subject": "Bestätigen Sie Ihre Abmeldung", "template": "newsletterUnsubscribe.htm" }, "fields": [ "newsletter.field.firstName", "newsletter.field.lastName", "newsletter.field.salutation" ], "importSubscribeDoubleOptIn": true, "unsubscribeAdminDoubleOptIn": true, "unsubscribeSelfDoubleOptIn": true, "welcomeEmail": { "fromAddress": "no-reply@websale.de", "fromName": "WEBSALE", "subject": "Herzlich Willkommen im Newsletter", "template": "newsletterWelcome.htm" } } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ----------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `blacklistSelfDoubleOptIn` | bool | Wenn sich jemand selbst vom Newsletter abmelden möchte, muss er dies per Bestätigungs-E-Mail (Double-Opt-In) bestätigen.
    default: `true` | | `doubleOptInEmailBlacklist` | object | Einstellungen für die Bestätigungs-E-Mail bei Abmeldung / Sperrung. | | `fromAddress` | string | Absender E-Mail der Bestätigungsmail. | | `fromName` | string | Absendername der Bestätigungsmail. | | `subject` | string | Betreff der Bestätigungsmail. | | `template` | string | Name / Datei des E-Mail-Templates, das verwendet werden soll. | | `doubleOptInEmailSubscribe` | object | Einstellungen für die Bestätigungs-E-Mail bei Anmeldung zum Newsletter. | | `fromAddress` | string | Absender E-Mail der Anmeldemail. | | `fromName` | string | Absendername der Anmeldemail. | | `subject` | string | Betreff der Anmeldemail. | | `template` | string | Name / Datei des E-Mail-Templates, das verwendet werden soll. | | `doubleOptInEmailUnsubscribe` | object | Einstellung für die Bestätigungs-E-Mail bei der Abmeldung vom Newsletter. | | `fromAddress` | string | Absender E-Mail der Abmeldungsmail. | | `fromName` | string | Absendername der Abmeldungsmail. | | `subject` | string | Betreff der Abmeldungsmail. | | `template` | string | Name / Datei des E-Mail-Templates, das verwendet werden soll. | | `fields` | multiAssoc | Verknüpfte Formularfelder für die Anmeldung zum Newsletter.
    Hier werden die unter `newsletter.field` definierten Felder referenziert.
    Ein eigenes Feld für E-Mail-Adresse muss nicht angegeben werden - diese wird stets automatisch unter dem Namen `email` übergeben.
    target: `newsletter.field` | | `importSubscribeDoubleOptIn` | bool | Auch importierte E-Mail-Adressen müssen ihre Anmeldung zum Newsletter per Bestätigungs-E-Mail bestätigen.
    default: `true` | | `unsubscribeAdminDoubleOptIn` | bool | Wenn ein Administrator jemanden vom Newsletter abmeldet, muss der Empfänger die Abmeldung per Bestätigungs-E-Mail bestätigen.
    default: `true` | | `unsubscribeSelfDoubleOptIn` | bool | Bei eigener Abmeldung vom Newsletter ist eine Abmeldung per Bestätigungs-E-Mail nötig.
    default: `true` | | `welcomeEmail` | object | Einstellungen für die Willkommens-E-Mail nach erfolgreich Anmeldung zum Newsletter. | | `fromAddress` | string | Absender E-Mail der Willkommensmail. | | `fromName` | string | Absendername der Willkommensmail. | | `subject` | string | Betreff der Willkommensmail. | | `template` | string | Name / Datei des E-Mail-Templates, das verwendet werden soll. | # payment - Zahlungsmethoden Source: https://dokumentation.websale.de/konfiguration/payment-zahlungsmethoden Der payment-Knoten bündelt die Zahlungskonfiguration: einzelne Zahlungsarten, Anzeigeregeln und Payment-Provider wie PayPal, Stripe oder Computop. Der Knoten `payment` bündelt die komplette Zahlungskonfiguration des Shops inklusive einzelner Zahlungsarten (Anzeige, Regeln) und Payment-Providern wie PayPal, Stripe oder Computop. *** ## `payment*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `payment` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "payment": { "payment": {}, "computopHosted": {}, "payPalCheckout": {}, "payPalPlus": {}, "stripe": {}, "transactionSettings": {} } } ``` #### Parameterbeschreibung | **Parameter** | **Beschreibung** | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `payment` | Steuert, welche Zahlungsarten im Shop angeboten werden. | | `computopHosted` | Konfiguriert die Anbindung an Computop. | | `payPalCheckout` | Konfiguriert die Anbindung an PayPal-Checkout. | | `payPalPlus` | Konfiguriert die Anbindung an PayPal Plus. | | `stripe` | Konfiguriert die Anbindung an Stripe. | | `transactionSettings` | Legt zentral fest, welche Funktionen von den Zahlungsanbietern unterstützt werden
    (z.B. `refund`, `manual`, `capturing`). | *** ## `payment.computopHosted` - Computop Hosted Payments Mit `payment.computopHosted` lässt sich Computop als gehostete Zahlungsseite einbinden. Der Knoten steuert beispielsweise Betriebsmodus (Live / Test), Verschlüsselung und Sprache / Template der Bezahlseite. #### Beispielkonfiguration (`payment.computopHosted.creditcard`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "callbackUrl": "", "capturingMode": "auto", "chDesc": "", "encryption": "blowfish", "hmacKey": "", "hostedCheckBoxDefaultChecked": false, "hostedTemplateName": "Websale", "id": "creditcard", "languageCode": "", "linkValidForSeconds": 500, "mode": "test", "passCredentialOnFile": true, "pwLarge": "", "sendIPAddr": true, "sendIPZone": true, "sendZone": true, "totalSumAddition": 0, "uid": "Websale" } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `callbackUrl` | string | Name des Shop-Templates (Views), auf das Computop den Kunden nach der Zahlung zurückleitet. Aus der URL dieses Templates wird die Rückkehr-Adresse gebaut; der Ausgang der Zahlung wird dabei als URL-Parameter `wsPaymentStatus` (`refresh` bzw. `cancel` bei Abbruch) angehängt. | | `capturingMode` | enum | Zulässige Werte:
    `auto`= die Zahlung wird in einem Schritt geprüft und direkt eingezogen.
    `manual`= der Betrag wird beim Checkout nur reserviert, aber noch nicht belastet. | | `chDesc` | string | Text, der beim Zahler erscheint (z.B. auf der Kartenabrechnung). | | `encryption` | enum | Zulässige Werte:
    `aes` = Moderne Verschlüsselungsoption.
    `blowfish`= ältere Verschlüsselungsoption, die noch unterstützt wird. | | `hmacKey` | string | Geheimschlüssel für Prüfungen der Daten gegenüber Computop. | | `hostedCheckBoxDefaultChecked` | bool | Setzt eine von Computop bereitgestellte Einverständnis-Checkbox auf aktiv oder nicht aktiv (`true` / `false`). | | `hostedTemplateName` | string | Name des Templates der gehosteten Computop-Bezahlseite. | | `id` | string | Eindeutige Kennung der Zahlart (z.B. `creditcard`). Frei wählbar. | | `languageCode` | string | Sprache der Hosted-Page (z.B. `de`, `en`). Leer = Standard von Computop. | | `linkValidForSeconds` | int | Gültigkeitsdauer des Zahlungslinks in Sekunden. | | `mode` | enum | Betriebsmodus der Computop-Integration.
    Zulässige Werte:
    -`test`= für Sandbox Tests
    - `live`= Verwendung in der Produktion. | | `passCredentialOnFile` | bool | Kennzeichnet "Kartendaten hinterlegt" für Folgetransaktionen, sofern unterstüzt. | | `pwLarge` | string | Zusätzliches Passwort gemäß Computop-Spezifikation.
    Das Passwort wird für die verschlüsselte Übertragung verwendet. | | `sendIPAddr` | bool | Übermittelt die Kunden-IP-Adresse an Computop. | | `sendIPZone` | bool | Übermittelt die aus der IP abgeleitete Zone (z.B. Land / Region) an Computop. | | `sendZone` | bool | Übermittelt die Shop-Zone (z.B. Lieferzone) an Computop. | | `totalSumAddition` | float | Fester Auf-/Abschlag in Währungseinheiten auf die Gesamtsumme der Zahlart. (z.B. `0.30`).
    `0`= kein Auf-/Abschlag.
    Nur möglich, wenn `capturingMode` den Wert `manual` hat. | | `uid` | string | Händler-/Account-ID bei Computop. | *** ## `payment.payment` - Zahlungsarten anlegen Der Knoten `payment.payment` fasst alle Zahlarten des Shops zusammen. Hier kann beispielsweise definiert werden, ob eine Zahlart aktiv ist, wie sie im Checkout heißen und aussehen soll, welcher Provider sie bedient und welche Regeln gelten. Zahlungsarten können an eine Währung oder Region gebunden sein (z. B. Bancontact: nur EUR, primär Belgien). Welche Währungen und Länder eine Zahlungsart unterstützt, bestimmt der Zahlungsdienstleister. Eine aktivierte Zahlungsart wird daher unabhängig von der Shop-Währung angeboten und führt eventuell beim Zahlungsdienstleister zu einem Fehler. Prüfen Sie daher vor der Aktivierung anhand der Anbieter-Dokumentation, ob die Zahlungsart zu Währung und Zielland Ihres Shops passt, und deaktivieren Sie nicht passende Methoden. #### Beispielkonfiguration (`payment.payment.paypalCheckout`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "availableByDefault": true, "basicCost": [ { "subtotal": 0, "cost": 2.5 }, { "subtotal": 50, "cost": 0 } ], "description": "", "longDescription": "", "discount": 0, "displayedPaymentTypes": null, "freeFields": null, "id": "paypalCheckout", "image": "", "labels": [""], "name": "", "onlineClearing": { "options": { "view": "paypal_checkout_pending.htm" }, "service": "payment.paypal-checkout" }, "orderText": "", "provider": "", "type": "", "validations": [ { "service": "paymentValidation.voucherDeny" } ] } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | --------------------------------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `active` | bool | Zahlart im Checkout ein / aus. | | `availableByDefault` | bool | Steuert, ob die Zahlart standardmäßig für alle Kunden verfügbar ist (Standard: `true`).
    Bei `false` steht die Zahlart Gästen und normalen Kundenkonten nicht zur Verfügung. Sie kann dann gezielt für einzelne Kundenkonten freigeschaltet werden, indem die Zahlart über die Admin-API in die Liste `enabledPaymentMethods` des Kontos aufgenommen wird (siehe [API-Referenz Kundendaten](/schnittstellen/admin-interface-api/api-referenz-kundendaten)).
    Umgekehrt kann eine standardmäßig verfügbare Zahlart über die Liste `blockedPaymentMethods` für einzelne Konten gesperrt werden. | | `id` | string | Eindeutige Kennung der Zahlart, z.B. `paypalCheckout` | | `name` | Textbaustein (string) | Anzeigename im Checkout, z.B. "PayPal".

    | | `orderText` (**demnächst verfügbar)** | Textbaustein (string) | Technischer Übergabewert für angebundene Drittsysteme, der mit der Bestellung exportiert wird.

    | | `labels` (**demnächst verfügbar)** | list / textbaustein (string) | Optionale Kurzkennzeichnung für die Zahlart, die im Checkout als Hinweis angezeigt werden kann.

    | | `type` (**demnächst verfügbar)** | string | Beschreibt die Art der Zahlabwicklung und hilft bei der Darstellung im Checkout.
    Übliche Werte sind z.B.: `online`- Zahlung läuft über einen Provider. `offline`- Zahlung wird manuell abgewickelt. | | `onlineClearing` | singleService | Verknüpft die Zahlart mit einer konkreten Online-Zahlungs-Engine und schaltet damit den Echtzeit-Zahlungsablauf frei.
    target: `payment` | | `provider` (**demnächst verfügbar)** | string | Technischer Provider-Key (z.B. `stripe`) | | `image` (**demnächst verfügbar)** | string | Icon/Logo-URL für die Zahlart. | | `basicCost` | list (object) | Kosten der Zahlart, gestaffelt nach der Zwischensumme des Warenkorbs. Pro Eintrag:
    - `subtotal` (float) - Zwischensumme, ab der der Eintrag gilt
    - `cost` (float) - Kosten der Zahlart in Währungseinheiten
    Im Beispiel oben kostet die Zahlart 2,50 und ist ab einer Zwischensumme von 50 kostenlos. Die Kosten fließen im Checkout in | | | | `$wsCheckout.sum.paymentCost` ein. | | -------------------------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `displayedPaymentTypes` | list (object) | Mit diesem Parameter können für eine Zahlungsart mehrere Einträge mit eigenem Namen, Icon, Bild oder Beschreibung hinterlegt werden.
    Dies ist vor allem dann relevant, wenn z.B. Payment-Provider wie Stripe direkt als Zahlungsarten konfiguriert werden, die enthaltenen Zahlungsmöglichkeiten jedoch außerhalb des Bestellablaufs separat dargestellt werden sollen
    - z.B. im Footer oder auf einer Zahlungsarten-Informationsseite.
    Die Anzeige der enthaltenen Zahlungsmöglichkeiten im Bestellablauf erfolgt in der Regel über den jeweiligen Provider.
    Pro Eintrag können folgende Eigenschaften gesetzt werden:
    - `name` - Anzeigename der Zahlungsoption
    - `image` - Pfad oder URL zu einem Bild / Icon der Zahlungsoption
    - `description` - Beschreibungstext der Zahlungsoption Die Ausgabe im Template erfolgt über die Variable des [\$wsConfig-Moduls](/frontend/referenz/module/wsconfig), über die die konfigurierten Einträge im Frontend an der gewünschten Stelle ausgegeben werden können. | | `validations` | multiService | Regeln und Checks für die Verfügbarkeit einer Zahlart
    (z.B. `paymentValidation.voucherDeny`- sperrt die Zahlart bei Gutschein-Warenkörben, `paymentValidation.userAgent` - schränkt die Zahlart auf bestimmte Geräte oder Browser ein).
    Mehr unter: [Validierungs- und Prüfservices](/konfiguration/validierungs-und-prufservices) target: `paymentValidation` | | `discount` (**demnächst verfügbar)** | float | Rabatt / Abschlag in Währungseinheiten. (z.B. `2.00`- Kunde Zahlt 2€ weniger mit dieser Zahlart). | | `description` | Textbaustein (string) | Längere Beschreibung / Hinweise zur Zahlungsart.

    | | `longDescription` | Textbaustein (string) | Noch ausführlichere Variante des Beschreibungstextes als `description`, beispielsweise für eine Zahlungsarten-Informationsseite oder ausführliche Hinweise.

    | | `freeFields` | list (string) | Freie Felder (z.B. zusätzliche Infos bei Rechnungskauf abfragen, wie Geburtstdatum oder Firmeninfos).
    Wird aktuell nur für Computop verwendet. | *** ## `payment.payPalCheckout` - PayPal Checkout Konfiguration Der Knoten `payment.payPalCheckout` konfiguriert den PayPal Checkout im Shop. Darunter beispielsweise die Aktivschaltung, die Einstellung des Modus (Live / Testmodus) und die Sprache. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "approvalTemplate": "", "brandName": "Websale AG", "cancelTemplate": "", "customerServiceInstructions": null, "denyPendingPayments": true, "dummyProductAddition": "dummy product", "errorTemplate": "", "expressCheckoutAllow": true, "expressCheckoutApplePayAllow": false, "expressCheckoutGooglePayAllow": false, "languageCode": "de-DE", "logoUrl": "", "mode": "sandbox", "payerId": "" } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------------------------------ | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `active` (**demnächst verfügbar)** | bool | Schaltet PayPal Checkout ein / aus. | | `payerId` | string | Paypal Merchant-ID des Händlerkontos. | | `dummyProductAddition` | string | Optionaler Zusatztext für Artikelnamen, falls PayPal eine Mindestangabe fordert. (z.B. Platzhalter bei leeren Namen). | | `denyPendingPayments` | bool | `true`- Bestellungen mit dem PayPal-Status "**pending**" werden abgelehnt bzw. nicht fortgeführt.
    `false`- "**pending**" wird zugelassen. | | `brandName` | string | Händlername, der angezeigt wird. | | `languageCode` | string | Anzeigesprache für PayPal (z.B. `de-DE`, `en-US`). | | `logoUrl` | string | URL zu einem Logo für die Darstellung im PayPal-Checkout. | | `customerServiceInstructions` | list (string) | Optionale Kundenhinweise, die im PayPal-Kontext angezeigt werden können. | | `mode` | enum | Betriebsmodus des PayPal-Checkouts.
    `sandbox`- Testmodus
    `live`- Produktivmodus
    Default: `sandbox` | | `approvalTemplate` | string | Name des Shop-Templates (Views), auf das der Kunde nach erfolgreicher Bestätigung der PayPal-Zahlung zurückgeleitet wird. Aus der URL dieses Templates wird die Rückkehr-Adresse gebaut, mit dem URL-Parameter `wsPaymentStatus=refresh`. Sie steht im Frontend als `approvalUrl` bzw. `expressApprovalUrl` in der Rückgabe von `$wsPayPalCheckout.loadData()` zur Verfügung. | | `errorTemplate` | string | Name des Shop-Templates (Views), auf das der Kunde bei einem Fehler im PayPal-SDK geleitet wird (URL-Parameter `wsPaymentStatus=error`). Im Frontend als `errorUrl` in der Rückgabe von `loadData()` verfügbar. | | `cancelTemplate` | string | Name des Shop-Templates (Views), auf das der Kunde nach dem Abbruch der PayPal-Zahlung geleitet wird (URL-Parameter `wsPaymentStatus=cancel`). Im Frontend als `cancelUrl` in der Rückgabe von `loadData()` verfügbar. | | `expressCheckoutAllow` | bool | Erlaubt PayPal Express (Direktkauf-Buttons z.B. im Warenkorb oder am Produkt).
    Default: `false` | | `expressCheckoutApplePayAllow` | bool | Erlaubt Apple Pay Express über die PayPal Commerce Platform. Ob Apple Pay Express im Frontend angeboten werden kann, gibt `$wsPayPalCheckout.expressCheckoutApplePay` aus. | | `expressCheckoutGooglePayAllow` | bool | Erlaubt Google Pay Express über die PayPal Commerce Platform. Ob Google Pay Express im Frontend angeboten werden kann, gibt `$wsPayPalCheckout.expressCheckoutGooglePay` aus. | *** ## `payment.payPalPlus` - PayPal Plus Konfiguration **PayPal Plus** war eine integrierte Zahlungslösung für Online-Händler, die PayPal, Lastschrift, Kreditkarte und Kauf auf Rechnung in einem Modul gebündelt hat. Inzwischen wurde PayPal Plus durch das neue [**PayPal Checkout**](/frontend/referenz/module/wspaypalcheckout) abgelöst. Die Integration wurde daher aus der aktuellen Software-Generation entfernt. Der Knoten `payment.payPalPlus` konfigurierte ehemals PayPal Plus im Shop. Darunter beispielsweise die Aktivschaltung, die Einstellung des Modus (Live / Testmodus) und die Sprache. **Beispielkonfiguration** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": false, "denyPendingPayments": true, "dummyProductAddition": "dummy product", "experienceProfileID": "", "merchantId": "", "mode": "sandbox" } ``` **Parameterbeschreibung** | **Parameter** | **Typ** | **Beschreibung** | | ------------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `active` (**demnächst verfügbar)** | bool | Schaltet PayPal Plus ein / aus. | | `merchantId` | string | Paypal Merchant-ID des Händlerkontos. | | `dummyProductAddition` | string | Optionaler Zusatztext für Artikelnamen, falls PayPal eine Mindestangabe fordert. (z.B. Platzhalter bei leeren Namen). | | `experienceProfileID` | string | ID eines PayPal-Experience-Profils (steuert u.a. Darstellung / Branding im PayPal-Flow). | | `denyPendingPayments` | bool | `true`- Bestellungen mit dem PayPal-Status "**pending**" werden abgelehnt bzw. nicht fortgeführt.
    `false`- "**pending**" wird zugelassen. | | `mode` | enum | Betriebsmodus von PayPalPlus.
    `sandbox`- Testmodus
    `live`- Produktivmodus
    Default: `sandbox` |
    *** ## `payment.stripe` - Stripe Konfiguration Der Knoten `payment.stripe` konfiguriert Stripe als Zahlungsdienstleister. Darunter beispielsweise die Aktivschaltung, die Einstellung des Modus (Live / Testmodus) und die Sprache. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": false, "autoRefundOnError": true, "mode": "sandbox", "savedPaymentMethods": { "displaySavedPaymentMethods": false, "maxDisplayedSavedPaymentMethods": 3, "paymentMethodAllowDelete": false, "paymentMethodAllowSave": false }, "targetAccount": "" } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | --------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `active` | bool | Schaltet den Stripe-Connector ein / aus. | | `mode` | enum | Betriebsmodus von Stripe.
    `sandbox`- Testmodus
    `live`- Produktivmodus
    Default: `sandbox` | | `targetAccount` | string | Stripe-Konto (z.B. Account-ID), an das Zahlungen gebucht werden. | | `autoRefundOnError` | bool | Aktiviert die automatische Rückerstattung, wenn während der Bestellverarbeitung seitens Websale ein Fehler auftritt.
    Bereits bezahlte, aber ungültige Bestellungen werden dadurch automatisch erstattet.
    Ist die Option deaktiviert, müssen solche Fälle manuell in Stripe rückerstattet werden.
    Default: `true` | | `savedPaymentMethods` | object | Steuerung der gespeicherten Zahlungsarten. | | `displaySavedPaymentMethods` | bool | Bereits gespeicherte Zahlungsarten im Checkout anzeigen. | | `maxDisplayedSavedPaymentMethods` | int | Maximal anzuzeigende gespeicherte Zahlungsarten.
    Default: `3` | | `paymentMethodAllowSave` | bool | Kunden dürfen neue Zahlungsmittel speichern. | | `paymentMethodAllowDelete` | bool | Kunden dürfen gespeicherte Zahlungsarten löschen. | *** ## `payment.transactionSettings` - Transaktionseinstellungen (global) Der Knoten `payment.transactionSettings` legt fest, welche Aktionen man im Store-Backend für Zahlungen ausführen kann - z.B. Rückzahlungen, Storno, Status aktualisieren oder Betrag einziehen. Für jeden Zahlungsanbieter wird konfiguriert, ob die jeweilige Aktion erlaubt ist und welche Eingaben dabei abgefragt werden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "clearers": [ { "name": "paypalCheckout", "options": [ { "name": "refund", "active": true, "additionalFields": [ { "name": "amount", "type": "decimal", "required": true }, { "name": "reason", "type": "string", "required": false } ]}, { "name": "cancel", "active": true, "additionalFields": [] }, { "name": "refresh", "active": true, "additionalFields": [] }, { "name": "capture", "active": false, "additionalFields": [] } ] }, { "name": "stripe", "options": [ { "name": "refund", "active": true, "additionalFields": [ { "name": "amount", "type": "decimal", "required": false }, { "name": "reference", "type": "string", "required": false } ]}, { "name": "cancel", "active": true, "additionalFields": [] }, { "name": "refresh", "active": true, "additionalFields": [] }, { "name": "capture", "active": true, "additionalFields": [ { "name": "amount", "type": "decimal", "required": true } ]} ] } ] } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------------- | ------------------------------------------------------------------------------------------------------- | | `clearers` | list (object) | Liste der angebundenen Zahlungsabwickler, für die Transaktionseinstellungen konfiguriert werden sollen. | | `name` | string | Technischer Name des Providers (z.B. `paypalCheckout`, `stripe`). | | `options` | list (object) | Definiert pro Provider die erlaubten Aktionen und deren Eingabefelder. | | `name` | enum | Mögliche Optionen: `refund`, `cancel`, `refresh`, `capture` | | `active` | bool | Aktiviert / Deaktiviert die Aktion im Store Backend. | | `name` | string | Feldname (z.B. `amount`) | | `type` | string | Datentyp des Feldes (z.B. `string`, `int`). | | `required` | bool | Definiert, ob es ein Pflichtfeld für die Aktion ist. | *** ## `payment.*` - Validierungs- und Prüfservices Die fest vorgegebenen Validierungs- und Prüfservices für den Knoten `payment` werden in Validations und Services verwendet. Eine Übersicht ist hier zu finden: [Validierungs- und Prüfservices](/konfiguration/validierungs-und-prufservices) # search - Sortierung und Filterung Source: https://dokumentation.websale.de/konfiguration/search-sortierung-und-filterung Der search-Knoten konfiguriert die interne Produktsuche und Listing-Seiten: Filter, Sortieroptionen, Treffer pro Seite sowie wiederverwendbare Regeln. Der Knoten `search` steuert die interne Produktsuche (nicht die WEBSALE Search) und Listing-Seiten im Shop. Er legt fest, welche Filter angeboten werden, welche Sortieroptionen verfügbar sind und wie viele Treffer pro Seite angezeigt werden. Er trennt die Einstellungen für Kategorie und Suchergebnisse und erlaubt die Definition einzelner Filter und Sortierregeln als wiederverwendbare Bausteine. *** ## `search*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `search`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "search": { "categoryNavigation": {}, "productSearchNavigation": {}, "productFilter": {}, "productSortOption": {} } } ``` #### Parameterbeschreibung | **Parameter** | **Beschreibung** | | ------------------------- | ------------------------------------------------------------------------------ | | `categoryNavigation` | Steuert Filter, Sortierung und Treffer pro Seite auf Kategorie-/Listingseiten. | | `productSearchNavigation` | Steuert Filter, Sortierung und Treffer pro Seite auf Suchergebnisseiten. | | `productFilter` | Definiert einen Filterbaustein. | | `productSortOption` | Definiert eine Sortierregel zur Verwendung in Kategorie- und Suchlisten. | *** ## `search.categoryNavigation` - Filter und Sortierung für Kategorieseiten Der Knoten `search.categoryNavigation` steuert, welche Filter und Sortierungen in Kategorieseiten verfügbar sind, welche Standardsortierung gilt sowie die Treffer pro Seite. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "defaultResultsPerPage": 16, "defaultSortOption": "search.productSortOption.relevance", "keepSortSettings": true, "productFilters": [ "search.productFilter.price", "search.productFilter.clothingLength", "search.productFilter.clothingOuterMaterial", "search.productFilter.brand" ], "resultsPerPageOptions": [16, 24, 32], "sortOptions": [ "search.productSortOption.relevance", "search.productSortOption.nameAsc", "search.productSortOption.nameDesc", "search.productSortOption.priceAsc", "search.productSortOption.priceDesc" ] } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | -------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `productFilters` | multiAssoc | Liste der verfügbaren Filter aus `search.productFilter`, beispielsweise Preis, Marke oder Material. Reihenfolge der Angaben entspricht der Reihenfolge im Frontend. | | `sortOptions` | multiAssoc | Liste der für den Nutzer wählbaren Sortierungen aus `search.productSortOption`, beispielsweise Relevanz, Name oder Preis auf- und absteigend. | | `defaultSortOption` | singleAssoc | Voreingestellte Sortierung aus `search.productSortOption` beim ersten Laden einer Kategorieseite, beispielsweise nach Relevanz. | | `resultsPerPageOptions` | list (uint) | Einstellbare Werte für „Treffer pro Seite“.
    Reihenfolge der Angaben entspricht der Reihenfolge im Frontend.
    Default: `[20, 50, 100, 200]` | | `defaultResultsPerPage` | uint | Voreinstellung der Treffer pro Seite (muss in `resultsPerPageOptions`ebenfalls angegeben sein).
    Default: `20` | | `keepSortSettings`
    | bool | Behalte die gewählte Sortierung / Limit pro Nutzer-Session bei.
    Default: `true` | ## `search.productFilter` - Produktfilter definieren Der Knoten `search.productFilter` definiert einzelne Filter für Listing-Seiten, beispielsweise Marke, Material, Preis oder Gewicht. Sie legen fest, welches Datenfeld gefiltert wird, wie der Filter funktioniert und ob es Abhängigkeiten zu anderen Filtern gibt. #### Beispielkonfiguration (`search.productFilter.weight`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "weight", "filterDependency": { "filter": null, "options": [] }, "type": { "keyword": { "optionsSort": "numResults", "multiSelect": true }, "range": null }, "target": { "field": "content.customProductField.weight", "special": null, "attribute": null }, "scoreBoost": 0, "optionsDirectlyDisplayable": false, "unit": "", "numInitialOptions": 0, "minOptions": 0 } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------------------------------------------ | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | Technischer Name des Filters, beispielsweise `brand` oder `price`. | | `filterDependency` | object | Definiert die Abhängigkeit zu einem anderen Filter. | | `filter` | singleAssoc | Referenz auf den abhängigen Filter aus `search.productFilter`. | | `options` | list (string) | Erlaubte Optionen des abhängigen Filters, bei deren Auswahl dieser Filter aktiv wird.
    Beispiel: Filter „Größe“ nur anzeigen, wenn die Kategorie Bekleidung gewählt ist:
    `{ "name": "size", "filterDependency": { "filter": "search.productFilter.category", "options": ["clothing"] } }` | | `type` | oneOf | Legt fest, wie der Filter arbeitet. | | `keyword` | object | Auswahlliste mit festen Werten, beispielsweise Marken oder Farben. | | `optionsSort` | enum | Sortierung der Optionswerte.
    Mögliche Angaben: `lexical`- alphabetische Sortierung `numResults`- Sortierung nach Trefferzahl `relevance`- Sortierung nach Relevanz | | `multiSelect` | bool | Mehrfachauswahl oder nur eine Option zulassen. | | `range` | object | Steuert einen zahlenbasierten Filter, beispielsweise Preis oder Gewicht. | | `inputType` | enum | Legt fest, wie Nutzer den Zahlenbereich des Filters wählen:
    `rangeonly`- Frei einstellbarer Bereich `optionsOnly`- Nur vorgegebene Stufen zur Auswahl `rangeAndOptions`- Kombiniert beides. | | `optionType` | enum | Bestimmt, woher die Zahlenbereichsstufen kommen:
    `static`- Feste Stufen manuell vorgeben. `dynamic`- Die Stufen werden automatisch aus vorhandenen Produktwerten berechnet. | | `dynamicSteps` | int | Gibt die Anzahl der dynamischen Stufen an.
    (nur, wenn bei `optionType` der Wert `dynamic`gewählt wurde.) | | `statisticOptions` | list (object) | Liste fester Zahlenbereichsstufen. | | `from` | float | Untere Grenze der Zahlenbereichsstufe. | | `to` | float | Obere Grenze der Zahlenbereichsstufe. | | `target` | oneOf | Legt fest, welches Produktfeld der Filter verwendet, beispielsweise ein Produktfeld oder ein Produktattribut. | | `field` | singleAssoc | Bindet den Filter an ein Produktfeld, beispielsweise `content.customProductField.weight`.
    Die Daten kommen aus `content.productField` \| `content.customProductField`. | | `special` | enum | Legt fest, ob nach Kategorie-ID (`categories`) oder Neuheiten (`new`) gefiltert wird. | | `attribute` | singleAssoc | Bindet den Filter an ein Produktattribut.
    Daten aus `content.productAttribute`. | | `scoreBoost`
    | float | Erhöht den Ranking-Einfluss ausgewählter Filterwerte auf die Ergebnisreihenfolge. | | `optionsDirectlyDisplayable`
    | bool | `true`- Optionsliste kann ohne „mehr anzeigen“ vollständig gezeigt werden.
    `false`- Optionsliste kann sich einklappen. | | `unit` | string | Einheit für die Anzeige, beispielsweise `kg`, `cm` oder `€`. | | `numInitialOptions` | uint | Anzahl initial sichtbarer Optionswerte, beispielsweise zuerst 5 anzeigen und den Rest aufklappen lassen. | | `minOptions` | uint | Mindestanzahl benötigter Optionswerte, damit der Filter überhaupt angezeigt wird. | ### Filter auf Preisfeldern Preisfelder können zeitgesteuerte Aktionspreise tragen. Für Filter und Sortierungen gilt dabei eine Einschränkung, die bei der Konfiguration zu beachten ist. Preisfelder werden im Suchindex ausschließlich mit ihrem Standardpreis abgelegt. Geplante Aktionspreise stehen im Index nicht zur Verfügung und wirken sich deshalb nicht auf Filter und Sortierungen aus. Ein Produkt mit laufendem Aktionspreis wird nach seinem Standardpreis einsortiert, auch wenn im Shop der niedrigere Aktionspreis angezeigt wird. Das Standardfeld `setPrice` ist entfallen, ebenso das zugehörige Indexfeld. Filter und Sortierungen, die darauf zeigen, müssen angepasst werden. Näheres beschreibt der Abschnitt [Set-Preis wird nicht mehr gespeichert](/schnittstellen/admin-interface-api/api-referenz-produkte#set-preis-wird-nicht-mehr-gespeichert). *** ## `search.productSearchNavigation` - Filter und Sortierung für Suchergebnisseiten Der Knoten `search.productSearchNavigation` definiert die Filter und die Sortierung auf Suchergebnisseiten. Einstellbar sind beispielsweise die Standard-Sortierung, die Treffer pro Seite sowie ein Limit für maximale Treffer pro Suche. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "defaultResultsPerPage": 16, "defaultSortOption": "search.productSortOption.relevance", "maxResults": 1000, "productFilters": [ "search.productFilter.price", "search.productFilter.clothingLength", "search.productFilter.clothingOuterMaterial", "search.productFilter.brand" ], "resultsPerPageOptions": [16, 24, 32], "sortOptions": [ "search.productSortOption.relevance", "search.productSortOption.nameAsc", "search.productSortOption.nameDesc", "search.productSortOption.priceAsc", "search.productSortOption.priceDesc" ] } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ----------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------- | | `productFilters` | multiAssoc | Verfügbare Filter für die Suche, beispielsweise Preis, Marke oder Material. Die Reihenfolge entspricht der Anzeige im Frontend. | | `sortOptions` | multiAssoc | Wählbare Sortierungen für den Nutzer, beispielsweise Relevanz oder Name und Preis auf- und absteigend. | | `defaultSortOption` | singleAssoc | Voreingestellte Sortierung der Suchergebnisse, beispielsweise Relevanz. | | `resultsPerPageOptions` | list (uint) | Auswahlwerte für „Treffer pro Seite“.
    Default: \[`20, 50, 100, 200`] | | `defaultResultsPerPage` | int | Voreinstellung der Treffer pro Seite (muss in `resultsPerPageOptions` enthalten sein). | | `maxResults` | int | Maximalzahl der berücksichtigten / anzeigbaren Treffer einer Suche. | *** ## `search.productSortOption` - Sortierungsmöglichkeit Der Knoten `search.productSortOption` definiert eine Sortiermöglichkeit für Kategorie- und Suchergebnisseiten. Er legt beispielsweise fest, wonach sortiert wird und in welcher Richtung. #### Beispielkonfiguration (`search.productSortOption.relevance`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "Beliebtheit", "target": { "field": null, "special": "relevance" } } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | Anzeigename der Sortierung im Frontend, beispielsweise „Beliebtheit“. | | `target` | oneOf | Legt fest, wonach sortiert wird. Es ist genau eine Variante wählbar:
    `field` oder `special` | | `field` | object | Sortierung nach einem konkreten Produktfeld. | | `field` | enum | Produktfeld aus `content.productField`\| `content.customProductField`, nach dem sortiert werden soll, beispielsweise der Preis. | | `direction` | enum | Sortierrichtung der Sortierung.
    `asc`= aufsteigend
    `desc`= absteigend | | `special` | enum | Systemsortierung nach Relevanz (`relevance`) | Eine Sortierung nach einem Preisfeld arbeitet auf dem Standardpreis. Aktionspreise werden nicht berücksichtigt, siehe [Filter auf Preisfeldern](#filter-auf-preisfeldern). # security - Sicherheitsregeln Source: https://dokumentation.websale.de/konfiguration/security-sicherheitsregeln Der security-Knoten bündelt sicherheitsrelevante Shopeinstellungen: Bot-Schutz, Hash- und Verschlüsselungsmethoden sowie Verwaltung von Schlüsseln und Secrets. Der Knoten `security` bündelt alle sicherheitsrelevanten Einstellungen des Shops. Bot-Schutz, Hash- und Verschlüsselungsmethoden und die Verwaltung von Schlüsseln/Secrets. *** ## `security*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `security`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "security": { "friendlyCaptchaV1": {}, "recaptchav3": {}, "method": {}, "actionGuard": {} } } ``` #### Parameterbeschreibung | **Parameter** | **Beschreibung** | | ------------------- | ------------------------------------------------- | | `friendlyCaptchaV1` | Bindet FriendlyCaptcha in den Shop ein. | | `recaptchav3` | Bindet Google reCAPTCHA in den Shop ein. | | `method` | Definiert, wie sensible Daten verarbeitet werden. | | `actionGuard` | Schützt einzelne Aktionen per Captcha-Prüfung. | *** ## `security.friendlyCaptchaV1` - Bot-Schutz mit FriendlyCaptcha Der Knoten `security.friendlyCaptchaV1` bindet Friendly Captcha in die Storefront ein, um Spam zu verhindern und Bots zu erkennen. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "friendlyCaptchaV1", "apiKey": "", "siteKey": "", "verifyUrl": "https://eu-api.friendlycaptcha.eu/api/v1/siteverify", "apiUrl": "https://eu-api.friendlycaptcha.eu/api/v1/puzzle" } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `name` | string | Frei wählbarer, interner Konfigurationsname. | | `apiKey` | string | Geheimer Server-Schlüssel für die Verifizierung bei FriendlyCaptcha. | | `siteKey` | string | Öffentlicher Schlüssel für die Einbindung von FriendlyCaptcha. | | `verifyUrl` | string | Endpunkt zur Server-Identifikation von FriendlyCaptcha. Default: `https://eu-api.friendlycaptcha.eu/api/v1/siteverify` | | `apiUrl` | string | Endpunkt zum Laden des “Puzzles”, die der Browser automatisch löst, um zu bestätigen, dass es sich nicht um einen Bot handelt. Default: `https://eu-api.friendlycaptcha.eu/api/v1/puzzle` | *** ## `security.method` - Sensible Daten verschlüsseln Der Knoten `security.method` definiert, wie sensible Daten verarbeitet werden (Hashing, verschlüsseltes Speichern). #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "encrypt": [ { "id": "token_v1", "secret": "ABC123" } ], "hash": [ { "id": "password_v1", "salt": "shop-wide-salt-a9c3f1", "pepper": "env:SECURITY_PEPPER" } ] } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------------- | -------------------------------------------------------------------------------------------------------------- | | `hash` | list (object) | Liste konfigurierter Hash-Verfahren für Einweg-Hashing (z.B. Passwörter). | | `id` | string | Technischer Name des Hash-Verfahrens, frei wählbar. (z.B. `password_v1`)
    Darf kein `#` enthalten. | | `salt` | string | Ein zusätzlicher, zufälliger Wert, der vor dem Hashen an die Daten angehängt wird. | | `pepper` | string | Ein geheimer Zusatzwert, der zusätzlich zum `salt` vor dem Hashen verwendet wird. | | `encrypt` | list (object) | Liste konfigurierter Verschlüsselungsverfahren für reversible Daten (z.B. Tokens, sensible Felder). | | `id` | string | Technischer Name des Verschlüsselungsverfahrens, frei wählbar. (z.B. `token_v1`)
    Darf kein `#` enthalten. | | `secret` | string | Geheimer Schlüssel für die Datenverschlüsselung. | *** ## `security.recaptchav3` - Bot-Schutz mit Google reCAPTCHA Der Knoten `security.recaptchav3` bindet Google reCAPTCHA in die Storefront ein, um Spam zu verhindern und Bots zu erkennen. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "minimumScore": 0.5, "name": "recaptchav3", "secretKey": "", "verifyUrl": "https://www.google.com/recaptcha/api/siteverify" } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `name` | string | Frei wählbare Kennung der Konfiguration. (z.B. Einsatzortbezogen wie “`recaptcha_checkout`”) | | `minimumScore` | float | Schwellwert für die Bewertung (`0.0` - `1.0`). Requests mit Score unter diesem Wert gelten als verdächtig. Liegt der Score unter dem angegebenen Wert, wird die Anfrage als verdächtig behandelt. Normalerweise wird ein Wert zwischen `0.3` (großzügigere Bewertung) bis `0.7` (strengere Bewertung) genommen. Mehr Informationen: [https://developers.google.com/recaptcha/docs/v3?hl=de#interpreting\_the\_score](https://developers.google.com/recaptcha/docs/v3?hl=de#interpreting_the_score) | | `secretKey` | string | Serverseitiger Geheimschlüssel von Google reCAPTCHA. | | `verifyUrl` | string | Endpunkt zur Token-Prüfung. In der Regel wird hier `https://www.google.com/recaptcha/api/siteverify` verwendet. | *** ## `security.actionGuard` - Captcha-Schutz für Aktionen Der Knoten `actionGuard` ermöglicht es, einzelne [Aktionen](/frontend/referenz/aktionen) mit einem Captcha zu schützen. Wird eine Aktion auf diese Weise konfiguriert, prüft das System bei jeder Ausführung, ob das Frontend einen gültigen Captcha-Token mitgeschickt hat. Wird die Aktion jedoch als Opt-In (z.B. über einen Bestätigungslink in einer Mail) ausgeführt, entfällt diese Prüfung. #### Beispielkonfiguration ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} actionName: Login captcha: service: captchaCheck.friendlyCaptchaV1 ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `actionName` | string | Name der Action, die durch den Captcha-Check geschützt werden soll. (z.B. `Login`) | | `captcha` | singleService (optional) | Referenz auf den zu verwendeten Captcha-Dienst. `captchaCheck` ist ein fest implementierter Service, der auf einen der konfigurierten Captcha-Dienste verweist - also entweder `captchaCheck.friendlyCaptchaV1` oder `captchaCheck.recaptchav3`. | # seoMetaData - Meta-Daten & Seo-Texte Source: https://dokumentation.websale.de/konfiguration/seometadata-meta-daten-seo-texte Der seoMetaData-Knoten steuert den Aufbau von Meta-Title und Meta-Description für Kategorien, Produkte, Startseite, freie Templates sowie CMS-Seiten aus Strapi per Bausteinen. Der Knoten `seoMetaData` steuert, wie Meta-Title und Meta-Description im Shop gebaut werden - für Kategorien, Produkte, die Startseite und frei definierte Templates. Statt jeden Text manuell zu pflegen, lassen sich Bausteine kombinieren, inklusive Trennzeichen und Reihenfolge. Der `seoMetaData`-Knoten gilt nicht nur für Kategorien, Produkte und die Startseite, sondern auch für CMS-Seiten, die über Strapi angelegt werden. CMS-Seiten werden im Shop als Views (Templates) ausgeliefert und nutzen daher dieselben `viewSchemes`-Bausteine für Meta-Title und Meta-Description. Die SEO-Angaben einer CMS-Seite (SEO-URL, Meta-Title, Meta-Description, Robots) werden in Strapi über das Meta-Info-Plugin gepflegt. Es ist auf jeder CMS-Seite vorhanden und stellt dafür feste, vorgegebene Felder bereit. Die eingetragenen Werte werden an den Shop übergeben und dort genauso behandelt wie die SEO-Daten von Produkten und Kategorien. Siehe [Übersicht - strapi CMS](/strapi-cms). *** ## `seoMetaData*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `seoMetaData`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "seoMetaData": { "categorySchemes": {...}, "generalSchemes": {...}, "productSchemes": {...}, "startPage": {...}, "viewSchemes": {...} } } ``` #### Parameterbeschreibung | **Parameter** | **Beschreibung** | | ----------------- | ---------------------------------------------------------------------- | | `categorySchemes` | Bausteine für Meta-Title und Description von Kategorien. | | `generalSchemes` | Definiert das globale SEO-Schema. | | `productSchemes` | Bausteine für Meta-Title und Description von Produkten. | | `startPage` | Bausteine für Meta-Title und Description für die Startseite. | | `viewSchemes` | Bausteine für Meta-Title und Description für Templates und CMS-Seiten. | *** ## `seoMetaData.categorySchemes` - Kategorie-Meta-Daten Der Knoten `seoMetaData.categorySchemes` liefert Bausteine für Meta-Title und Meta-Description von Kategorien. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "generalMetaDescription": false, "generalMetaTitle": false, "metaTitleForms": [ { "separator": "", "termType": "categoryField", "termData": { "categoryField": "content.categoryField:name" } }, { "separator": " | ", "termType": "customCategoryField", "termData": { "customCategoryField": "content.customCategoryField:brandTagline" } }, { "separator": " – ", "termType": "freeText", "termData": { "freeText": "Jetzt online kaufen" } } ], "metaDescriptionForms": [ { "separator": "", "termType": "customCategoryField", "termData": { "customCategoryField": "content.customCategoryField:metaIntro" } }, { "separator": " ", "termType": "categoryField", "termData": { "categoryField": "content.categoryField:descr" } }, { "separator": " ", "termType": "freeText", "termData": { "freeText": "Top Auswahl • Schneller Versand" } } ] } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------------ | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `metaTitleForms` | list (object) | Liste der “Bausteine” für den Meta-Titel einer Kategorie.
    Die Einträge werden der Reihe nach mit `separator` aneinandergefügt. | | `separator` | string | Trennzeichen, das vor diesem Term eingefügt wird (beispielsweise `-`). | | `termType` | enum | Art des Terms.
    Folgende Werte sind möglich:
    - `categoryField` - verweist auf Standard-Kategoriefelder (beispielsweise `name`, `descr`)
    - `customCategoryField` - verweist auf selbst angelegte Kategoriefelder
    - `freeText` - ein fester Text, der in `termData`definiert werden kann. | | `termData` | oneOf | Daten des Terms - je nach gewähltem `termType`. | | `freeText` | string | Selbst definierter, fester Text für `freeText`. | | `categoryField` | singleAssoc | Angabe eines Standard-Kategoriefelds aus `content.categoryField`. | | `customCategoryField` | singleAssoc | Angabe eines benutzerdefinierten Kategoriefelds aus `content.customCategoryField`. | | `generalMetaTitle` | bool | Nutzt den Standard-Meta-Title statt den obigen Bausteinen. | | `metaDescriptionForms` | list (object) | Bausteinliste für die Meta-Description - analog zu `metaTitleForms`. | | `separator` | string | Trennzeichen, das vor diesem Term eingefügt wird (beispielsweise `-`). | | `termType` | enum | Art des Terms.
    Folgende Werte sind möglich:
    - `categoryField` - verweist auf Standard-Kategoriefelder (beispielsweise `name`, `descr`)
    - `customCategoryField` - verweist auf selbst angelegte Kategoriefelder
    - `freeText` - ein fester Text, der in `termData`definiert werden kann. | | `termData` | oneOf | Daten des Terms - je nach gewähltem `termType`. | | `freeText` | string | Selbst definierter, fester Text für `freeText`. | | `categoryField` | singleAssoc | Angabe eines Standard-Kategoriefelds aus `content.categoryField`. | | `customCategoryField` | singleAssoc | Angabe eines benutzerdefinierten Kategoriefelds aus `content.customCategoryField`. | | `generalMetaDescription` | bool | Nutzt die Standard-Meta-Description statt den obigen Bausteinen. | *** ## `seoMetaData.generalSchemes` - Allgemeines SEO-Schema Der Knoten `seoMetaData.generalSchemes` definiert globale SEO-Texte und Muster. Dazu zählen Standard-Meta-Daten für die Startseite sowie „Formeln“ (Forms), mit denen beispielsweise Tab-Titel oder Snippets automatisch aus Kategorie-/Produktfeldern und freiem Text zusammengesetzt werden. Die Einträge in `initialTabs` sind die globalen Schemata der einzelnen Bereiche. Unter anderem greifen die [`viewSchemes`](#seometadata-viewschemes-template--cms-seiten-meta-daten) darauf zurück, wenn dort `generalMetaTitle` bzw. `generalMetaDescription` aktiviert ist. Der fünfte Eintrag liefert dann den View-Meta-Title, der sechste die View-Meta-Description. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "initialTabs": [ { "forms": [ { "separator": "-", "termData": { "categoryField": "content.categoryField.name" }, "termType": "categoryField" }, { "separator": null, "termData": { "categoryField": "content.categoryField.descr" }, "termType": "categoryField" } ] }, { "forms": [ { "separator": null, "termData": { "categoryField": "content.categoryField.descr" }, "termType": "categoryField" } ] }, { "forms": null }, { "forms": [ { "separator": null, "termData": { "productField": "content.productField.descr" }, "termType": "productField" } ] }, { "forms": [ { "separator": "-", "termData": { "freeText": "test" }, "termType": "freeText" }, { "separator": null, "termData": {}, "termType": "resourceId" } ] }, { "forms": [ { "separator": null, "termData": {}, "termType": "resourceId" } ] } ], "startPageMetaData": { "metaDescription": "", "metaTitle": "startseite beschreibung" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `initialTabs` | list (object) | Liste von Bausteinen für Tabs, aus denen der Shop SEO-Texte zusammenstellt. | | `forms` | list (object) | Die einzelnen Textbausteine, aus denen ein Tab zusammengesetzt wird. | | `separator` | string | Trennzeichen, das vor diesem Baustein eingefügt wird. (beispielsweise “`-`“) | | `termData` | oneOf | Daten des Terms - je nach gewähltem `termType`. | | `termType` | enum | Art des Terms.
    Folgende Werte sind möglich:
    - `categoryField` - verweist auf Standard-Kategoriefelder (beispielsweise `name`, `descr`)
    - `customCategoryField` - verweist auf selbst angelegte Kategoriefelder
    - `productField` - verweist auf ein Standardfeld eines Produkts (beispielsweise `name`)
    - `customProductField` - verweist auf selbst angelegte Produktfelder.
    - `resourceId` - fügt die Kennung der jeweiligen Ressource ein (beispielsweise eine Kategorie-ID, eine Produkt-ID oder den View-Namen).
    - `freeText` - ein fester Text, frei zu vergebender Text. | | `categoryField` | singleAssoc | Wert aus einem Standard-Kategoriefeld (beispielsweise `name`).
    Wert aus `content.categoryField`. | | `customCategoryField` | singleAssoc | Wert aus einem benutzerdefinierten Kategoriefeld.
    Wert aus `content.customCategoryField` | | `productField` | singleAssoc | Wert aus einem Standard-Produktfeld. (beispielsweise `descr`).
    Wert aus `content.productField`. | | `customProductField` | singleAssoc | Wert aus einem benutzerdefinierten Produktfeld.
    Wert aus `content.customProductField` | | `freeText` | string | Fest vorgegebener, selbst gewählter Text. | | `startPageMetaData` | object | Standard-Meta-Daten der Startseite. | | `metaDescription` | string | Meta-Description der Startseite. | | `metaTitle` | string | Meta-Title der Startseite | *** ## `seoMetaData.productSchemes` - Produkt-Meta-Daten Der Knoten `seoMetaData.productSchemes` steuert, wie Meta-Title und Meta-Description für Produktseiten zusammengesetzt werden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "generalMetaTitle": false, "generalMetaDescription": false, "metaTitleForms": [ { "separator": " – ", "termType": "productField", "termData": { "productField": "content.productField.name" } }, { "separator": " | ", "termType": "customProductField", "termData": { "customProductField": "content.customProductField.brand" } }, { "separator": null, "termType": "freeText", "termData": { "freeText": "Offizieller Shop" } } ], "metaDescriptionForms": [ { "separator": "", "termType": "productField", "termData": { "productField": "content.productField.descr" } }, { "separator": " • ", "termType": "customProductField", "termData": { "customProductField": "content.customProductField.keyFeatures" } } ] } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------------ | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `generalMetaTitle` | bool | Aktiviert einen globalen Meta-Title nach den definierten Bausteinen, falls am Produkt kein eigener Titel hinterlegt ist. | | `generalMetaDescription` | bool | Aktiviert eine globale Meta-Description nach den definierten Bausteinen, falls am Produkt keine Beschreibung hinterlegt ist. | | `metaTitleForms` | list (object) | Reihenfolge von Textbausteinen, aus denen der Meta-Title für Produktseiten generiert wird. | | `separator` | string | Trennzeichen, das vor diesem Baustein eingefügt wird. (beispielsweise “`-`“) | | `termType` | enum | Art des Terms.
    Folgende Werte sind möglich:
    - `productField` - verweist auf ein Standardfeld eines Produkts (beispielsweise `name`).
    - `customProductField` - verweist auf selbst angelegte Produktfelder.
    - `freeText` - ein fester Text, frei zu vergebender Text. | | `termData` | oneOf | Daten des Terms - je nach gewähltem `termType`. | | `metaDescriptionForms` | list (object) | Reihenfolge von Textbausteinen, aus denen die Meta-Description für Produktseiten generiert wird. | | `separator` | string | Trennzeichen, das vor diesem Baustein eingefügt wird. (beispielsweise “`-`“) | | `termType` | enum | Art des Terms.
    Folgende Werte sind möglich:
    - `productField` - verweist auf ein Standardfeld eines Produkts (beispielsweise `name`).
    - `customProductField` - verweist auf selbst angelegte Produktfelder.
    - `freeText` - ein fester Text, frei zu vergebender Text. | | `termData` | oneOf | Daten des Terms - je nach gewähltem `termType`. | *** ## `seoMetaData.startPage` - Startseite Meta-Daten Der Knoten `seoMetaData.startPage` definiert die SEO-Texte für die Startseite. Hier können Meta-Title und Meta-Description hinterlegt werden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "metaTitle": "Willkommen im WEBSALE Demo-Shop – Neuheiten & Bestseller", "metaDescription": "Jetzt Neuheiten, Bestseller und attraktive Angebote entdecken. Schneller Versand, sichere Zahlung und erstklassiger Service." } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ----------------- | ------- | ----------------------------------------------------------------------------- | | `metaTitle` | string | SEO-Titel der Startseite (kurz und prägnant, ideal ca. 50-60 Zeichen). | | `metaDescription` | string | SEO-Beschreibung der Startseite (zusammenfassend, ideal ca. 140-160 Zeichen). | *** ## `seoMetaData.viewSchemes` - Template- & CMS-Seiten-Meta-Daten Der Knoten `seoMetaData.viewSchemes` definiert, wie Meta-Title und Meta-Description für Views automatisch zusammengesetzt werden. Views sind die statischen Shop-Seiten (Templates), beispielsweise Kontakt, AGB oder Impressum. Als Bausteine stehen hier ein fester Text (`freeText`) und der Name der jeweiligen View (`resourceId`) zur Verfügung. Die so generierten Werte dienen als Vorbelegung. Im Admin Interface können Meta-Title und Meta-Description zusätzlich je View manuell gepflegt werden. Manuell gesetzte Werte bleiben erhalten und werden nicht durch die generierten Bausteine überschrieben. **Gilt auch für CMS-Seiten aus Strapi:** Über Strapi angelegte CMS-Seiten werden im Shop als Views ausgeliefert. Die hier definierten `viewSchemes`-Bausteine greifen daher auch für diese Seiten. Die SEO-Angaben je CMS-Seite (SEO-URL, Meta-Title, Meta-Description, Robots) werden in Strapi über das Meta-Info-Plugin gepflegt. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "generalMetaDescription": false, "generalMetaTitle": false, "metaTitleForms": [ { "separator": null, "termType": "freeText", "termData": { "freeText": "Onlineshop" } }, { "separator": " | ", "termType": "resourceId", "termData": {} } ], "metaDescriptionForms": [ { "separator": null, "termType": "freeText", "termData": { "freeText": "Infos & Service" } }, { "separator": null, "termType": "resourceId", "termData": {} } ] } ``` Mit dieser Beispielkonfiguration entsteht für die View `kontakt.htm` der Meta-Title „Onlineshop | kontakt.htm". Der Baustein `freeText` liefert den festen Text „Onlineshop", der Baustein `resourceId` fügt den View-Namen ein und das Trennzeichen `" | "` verbindet beide. #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `generalMetaDescription` | bool | Bei `true` wird die Meta-Description nicht aus den hier definierten `metaDescriptionForms` gebaut, sondern aus dem globalen View-Schema in [`seoMetaData.generalSchemes`](#seometadata-generalschemes-allgemeines-seo-schema).
    Bei `false` gelten die Bausteine dieses Knotens. | | `generalMetaTitle` | bool | Bei `true` wird der Meta-Title nicht aus den hier definierten `metaTitleForms` gebaut, sondern aus dem globalen View-Schema in [`seoMetaData.generalSchemes`](#seometadata-generalschemes-allgemeines-seo-schema).
    Bei `false` gelten die Bausteine dieses Knotens. | | `metaTitleForms` | list (object) | Reihenfolge von Textbausteinen, aus denen der Meta-Title für Templates und CMS-Seiten generiert wird. | | `separator` | string | Trennzeichen, das vor diesem Baustein eingefügt wird. (beispielsweise “`-`“) | | `termType` | enum | Art des Terms.
    Folgende Werte sind möglich:
    - `resourceId` - fügt den Namen der jeweiligen View ein (beispielsweise `kontakt.htm`).
    - `freeText` - ein fester Text, frei zu vergebender Text. | | `termData` | oneOf | Daten des Terms - je nach gewähltem `termType`. | | `metaDescriptionForms` | list (object) | Reihenfolge von Textbausteinen, aus denen die Meta-Description für Templates und CMS-Seiten generiert wird. | | `separator` | string | Trennzeichen, das vor diesem Baustein eingefügt wird. (beispielsweise “`-`“) | | `termType` | enum | Art des Terms.
    Folgende Werte sind möglich:
    - `resourceId` - fügt den Namen der jeweiligen View ein (beispielsweise `kontakt.htm`).
    - `freeText` - ein fester Text, frei zu vergebender Text. | | `termData` | oneOf | Daten des Terms - je nach gewähltem `termType`. | # statistics - Statistikdaten Source: https://dokumentation.websale.de/konfiguration/statistics Statistik-Konfiguration im WEBSALE-Shop: Tracking-Anbieter einbinden, Conversion-Events steuern und Statistikdaten für Auswertungen bereitstellen. Der Abschnitt `statistics` bündelt die Einstellungen rund um die Statistikdaten Ihres Shops. *** ## `statistics*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `statistics` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "statistics": { "dataRetention": {...} } } ``` #### Parameterbeschreibung | **Parameter** | **Beschreibung** | | --------------- | --------------------------------------------------------------------------------- | | `dataRetention` | Aufbewahrungsdauer der Statistikdaten je Zeitebene (Stunden-/Tages-/Monatswerte). | *** ## `statistics.dataRetention` - Aufbewahrung von Statistikdaten In diesem Konfigurationsknoten wird festgelegt, wie lange Statistikdaten je Zeitebene aufbewahrt werden. In der Statistik fallen laufend Zahlen zu Besuchen, Bestellungen und Umsätzen an. Diese können auf folgenden Zeitebenen gespeichert werden: * Stundenwerte - ein Datenpunkt je Stunde (beispielsweise zur Auswertung von Stoßzeiten oder Kampagnen), * Tageswerte - ein Datenpunkt je Tag (beispielsweise zum Vergleich zwischen Black Friday 2025 und 2024), * Monatswerte - ein Datenpunkt je Monat (beispielsweise zum Vergleich von Umsatzwachstum und Kundengewinnung). Für jede dieser Ebenen legen Sie die Aufbewahrungsfrist getrennt fest. Die Ebenen unterscheiden sich in Bezug auf Detailgrad und Speicherbedarf. Stundenwerte sind sehr detailliert, benötigen aber viel Speicherplatz (24 Datenpunkte pro Tag) und sind vor allem für kurzfristige Analysen interessant. Monatswerte hingegen sind grob, benötigen kaum Speicherplatz (12 Datenpunkte pro Jahr) und eignen sich für die Auswertung von Trends über mehrere Jahre. Die Standardwerte sind so gewählt, dass die feinen Stundenwerte am kürzesten und die groben Monatswerte am längsten gespeichert werden. So bleibt die gespeicherte Datenmenge klein, ohne dass der langfristige Trend verloren geht. `dataRetention` ist ein Singleton und wird einmal pro Shop konfiguriert. #### Beispielkonfiguration `statistics.dataRetention` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "retainHourlyInMonths": 3, "retainDailyInMonths": 24, "retainMonthlyInMonths": 60, "monthlyUnlimitedRetention": false } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `retainHourlyInMonths` | uint | Aufbewahrungsdauer der Stundenwerte in Monaten. Stundenwerte sind die feinste und speicherintensivste Ebene.
    Das Maximum begrenzt sie auf höchstens ein Jahr.
    Mögliche Werte: `0` - `12`
    Default: `3` | | `retainDailyInMonths` | uint | Aufbewahrungsdauer der Tageswerte in Monaten.
    Default: `24` | | `retainMonthlyInMonths` | uint | Aufbewahrungsdauer der Monatswerte in Monaten.
    Default: `60` | | `monthlyUnlimitedRetention` | bool | Aktiviert die unbegrenzte Aufbewahrung der Monatswerte.
    `true` - Monatswerte werden dauerhaft aufbewahrt.
    `false` - Monatswerte werden gemäß `retainMonthlyInMonths` aufbewahrt.
    Default: `false` | # statistics - Statistikdaten Source: https://dokumentation.websale.de/konfiguration/statistics-statistikdaten Konfiguration des statistics-Knotens: Aufbewahrungsdauer der Statistikdaten je Zeitebene (Stunden-, Tages- und Monatswerte) im WEBSALE Shop. Der Abschnitt `statistics` bündelt die Einstellungen rund um die Statistikdaten Ihres Shops. Aktuell steuert er die **Datenhaltung**: Über den Unterknoten `dataRetention` legen Sie fest, wie lange die erfassten Statistikwerte je Zeitebene aufbewahrt werden. Damit bestimmen Sie, wie weit Auswertungen zeitlich zurückreichen und wie viel Speicher die Statistik belegt. ## `statistics*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `statistics` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "statistics": { "dataRetention": {...} } } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | --------------- | --------------------------------------------------------------------------------- | | `dataRetention` | Aufbewahrungsdauer der Statistikdaten je Zeitebene (Stunden-/Tages-/Monatswerte). | ## `statistics.dataRetention` - Aufbewahrung von Statistikdaten Dieser Abschnitt legt fest, wie lange Statistikdaten je Zeitebene aufbewahrt werden. WEBSALE hält die Werte in drei Granularitäten vor: **Stundenwerte**, **Tageswerte** und **Monatswerte**. Jede Ebene wird über einen eigenen Parameter gesteuert. Das Leitprinzip lautet: je älter die Daten, desto gröber dürfen sie sein. Die feinste Ebene (Stundenwerte) ist am speicherintensivsten und nur kurzfristig relevant, daher läuft sie früh aus. Die gröbste Ebene (Monatswerte) ist sehr klein und langfristig wertvoll, daher bleibt sie lange erhalten. So bleibt die Datenmenge beherrschbar, ohne den langfristigen Trend zu verlieren. `dataRetention` ist ein Singleton und wird einmal pro Shop konfiguriert. #### Beispielkonfiguration `statistics.dataRetention` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "retainHourlyInMonths": 3, "retainDailyInMonths": 24, "retainMonthlyInMonths": 60, "monthlyUnlimitedRetention": false } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `retainHourlyInMonths` | uint | Aufbewahrungsdauer der Stundenwerte in Monaten. Stundenwerte sind die feinste und speicherintensivste Ebene; das Maximum begrenzt sie auf höchstens ein Jahr.
    Mögliche Werte: `0` - `12`
    Default: `3` | | `retainDailyInMonths` | uint | Aufbewahrungsdauer der Tageswerte in Monaten.
    Default: `24` | | `retainMonthlyInMonths` | uint | Aufbewahrungsdauer der Monatswerte in Monaten.
    Default: `60` | | `monthlyUnlimitedRetention` | bool | Aktiviert die unbegrenzte Aufbewahrung der Monatswerte.
    `true` - Monatswerte werden dauerhaft aufbewahrt.
    `false` - Monatswerte werden gemäß `retainMonthlyInMonths` aufbewahrt.
    Default: `false` | **Auslieferungsstandard und Begründung** Mit neuen Shops werden die oben gezeigten Werte ausgeliefert. Sie sind je Zeitebene bewusst gewählt: * **Stundenwerte - 3 Monate:** feinste, speicherintensivste Ebene (24 Punkte/Tag). Nur kurzfristig relevant (Stoßzeiten, Kampagne von gestern); deckt ein Quartal ab. * **Tageswerte - 24 Monate:** Arbeitsebene des Händlers. Zwei Jahre ermöglichen den Vorjahresvergleich auf Tagesbasis und decken saisonale Effekte ab. * **Monatswerte - 60 Monate (5 Jahre):** strategische Ebene, sehr klein im Speicher (12 Punkte/Jahr). Liefert Mehrjahres-Trends wie Umsatzentwicklung und Kundengewinnung. * **`monthlyUnlimitedRetention` - `false`:** Unbegrenztes Datenwachstum soll eine bewusste Entscheidung des Händlers sein, kein stiller Default. # storefrontApi - Storefront-API Source: https://dokumentation.websale.de/konfiguration/storefrontapi-storefront-api Der storefrontApi-Knoten bündelt alle Konfigurationsmöglichkeiten der Storefront-API im WEBSALE Shopsystem für die Anbindung externer Frontends. Der Knoten `storefrontApi` bündelt die Konfigurationsmöglichkeiten für die Storefront-API. *** ## `storefrontApi*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `storefrontApi` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "storefrontApi": { "redirects": {}, "catalogApiSettings": {} } } ``` #### Parameterbeschreibung | **Parameter** | **Beschreibung** | | -------------------- | --------------------------------------------------------------------------------------- | | `redirects` | Definiert Template-Weiterleitungen (`identifier` → Ziel-Template). | | `catalogApiSettings` | Steuert die Katalog-Endpunkte der Storefront-API und die darüber auslieferbaren Felder. | *** ## `storefrontApi.redirects` - Template-Weiterleitung Der Knoten `storefrontApi.redirects` definiert, welcher Name (`identifier`) auf welches Template im Shop verweist. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "identifier": "checkout", "targetTemplateName": "checkout.htm", "parameters": { "step": "1" } } ``` **Parameterbeschreibung** | **Parameter** | **Typ** | **Beschreibung** | | -------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `identifier` | string | Freier Name der Weiterleitung, wird als `viewIdentifier` im API-Aufruf verwendet.
    Mehr dazu: [Storefront API Session-Handling](/schnittstellen/storefront-api/storefront-api-session-handling) | | `targetTemplateName` | string | Pfad/Name der Ziel-Template-Datei (z. B. `checkout.htm`) | | `parameters` | object | Optionale Werte, die dem erzeugten Link als **Query-Parameter** angehängt werden. Im Template stehen sie wie alle URL-Parameter zur Verfügung, z. B. über `$wsViews.current.paramList`. Hierüber erhält eine mehrstufige Zielseite ihren Einstiegsschritt. | Mit der Beispielkonfiguration oben liefert `session/prepareRedirect` einen Link der Form: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://ihr-shop.de/checkout?step=1&sessionKey=... ``` Die Werte aus `parameters` sind fest konfiguriert und für jeden Aufruf gleich. Werte, die je Aufruf unterschiedlich sind, übergeben Sie stattdessen im Request-Body von [`session/prepareRedirect`](/schnittstellen/storefront-api/storefront-api-session-handling) — diese landen jedoch in der Session und nicht in der URL. *** ## `storefrontApi.catalogApiSettings` - Steuerung der Katalog-Endpunkte Der Knoten `storefrontApi.catalogApiSettings` steuert, welche Katalog-Endpunkte in der Storefront-API verfügbar sind und welche Felder darüber ausgeliefert werden dürfen. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "categoryFieldWhitelist": null, "enableCategoryDataEndpoint": true, "enableCategoryWhitelist": false, "enableProductDataEndpoint": true, "enableProductWhitelist": false, "productFieldWhitelist": null } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ---------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enableProductDataEndpoint` | bool | Aktiviert/deaktiviert den Produkt-Endpunkt der Storefront-API. | | `enableCategoryDataEndpoint` | bool | Aktiviert/deaktiviert den Kategorien-Endpunkt der Storefront-API. | | `enableProductWhitelist` | bool | Schaltet eine Whitelist für auslieferbare Produktfelder ein.
    Wenn `true`, werden nur Felder aus `productFieldWhitelist` zurückgegeben.
    Default: `false` | | `enableCategoryWhitelist` | bool | Schaltet eine Whitelist für auslieferbare Kategoriefelder ein.
    Wenn `true`, werden nur Felder aus `categoryFieldWhitelist` zurückgegeben.
    Default: `false` | | `productFieldWhitelist` | multiAssoc | Liste erlaubter Produktfelder aus `content.productField` und/oder `content.customProductField`.
    Wirkt nur, wenn `enableProductWhitelist = true`. | | `categoryFieldWhitelist` | multiAssoc | Liste erlaubter Kategoriefelder aus `content.categoryField` und/oder `content.customCategoryField`.
    Wirkt nur, wenn `enableCategoryWhitelist = true`. | # system - Grundlegende Systemkonfiguration Source: https://dokumentation.websale.de/konfiguration/system Der system-Knoten enthält grundlegende, infrastrukturelle WEBSALE-Konfigurationen, die das technische Systemverhalten unabhängig von Shop-Inhalten steuern. Der Knoten `system` enthält grundlegende technische Konfigurationen des Shops. Diese steuern das Systemverhalten auf infrastruktureller Ebene - unabhängig von Shop-Inhalten. Die Konfiguration erfolgt im Admin-Interface im Bereich "Storefront-API". *** ## `system*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `system` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "system": { "trustedProxies": { ... } } } ``` #### Parameterbeschreibung | **Parameter** | **Beschreibung** | | ---------------- | --------------------------------------------------------------------------------------------------------------- | | `trustedProxies` | Konfiguration der vertrauenswürdigen Proxy-Server, von denen der `X-Forwarded-For` HTTP-Header akzeptiert wird. | *** ## `system.trustedProxies` - Vertrauenswürdige Proxy-Server In manchen Setups ist der Shop nicht direkt über das Internet erreichbar, sondern über einen vorgelagerten Server. Dies ist beispielsweise der Fall, wenn eine Agentur das Shop-Frontend auf ihrer eigenen Infrastruktur hostet. In diesem Fall sieht der Shop bei eingehenden Anfragen nicht die IP-Adresse des Endkunden, sondern nur die des Agentur-Servers. Das ist problematisch, sobald der Shop IP-Adressen sperren muss, beispielsweise bei zu vielen fehlerhaften Login-Versuchen oder auffälligen Zahlungsvorgängen. Da alle Anfragen in diesem Fall von derselben Server-IP der Agentur kommen, würde eine Sperre den Shop somit für alle Kunden unzugänglich machen. **Warum ist eine Whitelist notwendig?**\ Der Shop darf den `X-Forwarded-For-Header` nicht von beliebigen Servern akzeptieren. Ein Angreifer könnte diesen Header selbst setzen und dem Shop eine gefälschte IP-Adresse übermitteln, wodurch IP-basierte-Schutzmechanismen umgangen würden. Deshalb wird mit `trustedProxies` eine Whitelist gepflegt. Nur Server, deren IP-Adresse dort eingetragen ist, dürfen den `X-Forwarded-For-Header` setzen. Von allen anderen Servern wird dieser Header ignoriert. Wenn der Shop hinter einem Proxy-Server betrieben wird und `trustedProxies` nicht korrekt konfiguriert ist, können IP-Sperren die gesamte Proxy-IP betreffen und somit den Shop für alle Kunden sperren. Stellen Sie in diesem Fall sicher, dass der Proxy-Server die echte Client-IP per `X-Forwarded-For` weiterleitet und seine IP hier eingetragen ist. #### Beispielkonfiguration `system.trustedProxies` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "addresses": [ "13.196.200.101", "13.196.0.0/16", "1234:5678:9abc:def0::1", "1234:5678:9abc:def0::/64" ] } ``` #### Parameterbeschreibung | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `addresses` | list (string) | Liste der IP-Adressen oder IP-Subnetze, von denen der [X-Forwarded-For-Header](https://de.wikipedia.org/wiki/X-Forwarded-For) akzeptiert wird.
    Unterstützt werden einzelne IPv4- und IPv6-Adressen sowie CIDR-Subnetze.

    Default: `[]` | #### Unterstützte IP-Formate | **Format** | **Beispiel** | **Beschreibung** | | ------------------- | -------------------------- | ------------------------------------------------------------ | | IPv4-Adresse | `13.196.200.101` | Eine einzelne, explizite IPv4-Adresse. | | IPv4-Subnetz (CIDR) | `13.196.0.0/16` | Alle Adressen im Bereich
    `13.196.0.0 - 13.196.255.255` | | IPv6-Adresse | `1234:5678:9abc:def0::1` | Eine einzelne, explizite IPv6-Adresse. | | IPv6-Subnetz (CIDR) | `1234:5678:9abc:def0::/64` | Ein IPv6-Subnetz in CIDR-Notation. | Subnetze in [CIDR-Notation](https://de.wikipedia.org/wiki/Classless_Inter-Domain_Routing) sind besonders dann sinnvoll, wenn ein vorgelagerter Server eine dynamische IP aus einem bekannten, festen Adressbereich verwendet. *** ## Weiterführende Links * [X-Forwarded-For](https://de.wikipedia.org/wiki/X-Forwarded-For) * [Classless Inter-Domain-Routing](https://de.wikipedia.org/wiki/Classless_Inter-Domain_Routing) # urls - URL (Webadressen) Source: https://dokumentation.websale.de/konfiguration/urls-url-webadressen Der urls-Knoten bündelt die URL-Konfiguration: hreflang-Alternativen, Weiterleitungen, veraltete URLs sowie Aufbau und Bereinigung der SEO-URLs. Der Knoten `urls` bündelt die URL-Konfiguration des Shops. Er umfasst Sprach-/Länder-Alternativen per `hreflang`, Weiterleitungen sowie fehlerhafte oder veraltete URLs und den Aufbau und die Bereinigung der SEO-URLs (Struktur, Trennzeichen, Parameterbereinigung). *** ## `urls*` - Grundstruktur Nachfolgend der Grundaufbau des Knotens `urls` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "urls": { "hreflang": {}, "redirects": {}, "urls": {} } } ``` #### Parameterbeschreibung | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------------------------------------------------------- | | `hreflang` | Steuert, welche Seiten-URLs Suchmaschinen per `hreflang` kennen sollen. | | `redirects` | Steuert, wie der Shop auf fehlerhafte oder nicht mehr gültige URLs reagieren soll. | | `urls` | Steuert, wie sprechende URLs im Shop aufgebaut und bereinigt werden. | *** ## `urls.hreflang` - Sprach-/Länder-Alternativen für Seiten-URLs Über diesen Knoten wird gesteuert, welche alternativen Seiten-URLs (z. B. DE/AT/CH/EN) Suchmaschinen per `hreflang` zu einer Seite kennen sollen. Dazu werden Subshops zu Gruppen zusammengefasst. Pro Gruppe lässt sich festlegen, ob Produkte/Kategorien automatisch oder manuell zugeordnet werden und in welchem Exportformat (CSV/JSON) die Zuordnungen ausgegeben werden sollen. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "collectInfo": true, "subshopGroups": [ { "categoryAlloc": "automatic", "checkMode": true, "fileNameCategory": "catAlloc.csv", "fileNameProduct": "prodAlloc.csv", "fileType": "csv", "groupId": "hrefGroup", "groupName": "Href-Group", "productAlloc": "automatic", "subshops": [ { "default": true, "subshopId": "deutsch" }, { "default": false, "subshopId": "englisch" } ] } ] } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------ | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `collectInfo` | bool | Wenn diese Option aktiviert wird, sammelt das System Informationen darüber, welche Sprach-/Länderversionen zu welcher Seite gehören und ob die Verknüpfungen korrekt gesetzt sind - das hilft beim finden von Fehlern.
    Default: `true` | | `subshopGroups` | list (object) | Liste der Subshop-Gruppen, die für hreflang zusammengefasst werden. | | `groupId` | string | Eindeutige Kennung der hreflang-Gruppe innerhalb von `subshopGroups`.
    Frei wählbar. | | `groupName` | string | Lesbarer Name der hreflang-Gruppe. | | `checkMode` | bool | Schaltet Prüfungen ein, die typische Fehler in den Sprach-/Länder-Zuordnungen finden. | | `productAlloc` | enum | Legt fest, wie sprach-/subshop-spezifische Gegenstücke desselben Produkts (hreflang-Varianten) verknüpft werden.
    `automatic` - Automatische Zuordnung
    `manual` - Zuordnung wird manuell gepflegt (z.B. per Datei/Liste).
    Default: `automatic` | | `categoryAlloc` | enum | Legt fest, wie sprach-/subshop-spezifische Kategorien verknüpft werden.
    `automatic` - Automatische Zuordnung
    `manual` - Zuordnung wird manuell gepflegt (z.B. per Datei/Liste).
    Default: `automatic` | | `fileType` | enum | Legt das Exportformat der Hreflang-Zuordnungen für Kategorien und Produkte fest.
    `csv` - stellt die Export-Datei im csv-Format bereit
    `json` - stellt die Export-Datei im json-Format bereit | | `fileNameProduct` | string | Legt den Dateinamen für den Export der Produktzuordnungen fest. | | `fileNameCategory` | string | Legt den Dateinamen für den Export der Kategoriezuordnungen fest. | | `subshops` | list (object) | Enthält eine Liste der verfügbaren Sprach-/Subshops. | | `subshopId` | string | ID des Subshops (z.B. `de`, `en`) | | `default` | bool | Markiert die primäre Sprache/Region. Default: `false` | *** ## `urls.redirects` - Weiterleitungen für fehlerhafte URLs Über den Unterknoten `redirects` wird gesteuert, wie der Shop auf nicht mehr gültige oder fehlerhafte URLs reagiert (z. B. gelöschte Produkte/Kategorien oder veraltete Links). Hier wird festgelegt, welches Fehlerseiten-Template verwendet werden soll, ob nach Möglichkeit automatisch auf die Elternkategorie umgeleitet wird und auf welche Seite im Allgemeinen als Fallback weitergeleitet wird. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "errorPageTemplate": "error.htm", "redirectFallback": "errorPage", "redirectToParentCategory": true } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | -------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `errorPageTemplate` | string | Name des Templates, das für Fehlerseiten (z.B. 404-Seite) verwendet wird. | | `redirectFallback` | string | Fallback-Ziel, wenn keine spezifische Weiterleitung greift.
    `startPage` - im Fehlerfall wird auf die Startseite des Shops weitergeleitet
    `errorPage` - Im Fehlerfall wird auf die Default-Fehlerseite weitergeleitet Default: `startPage` | | `redirectToParentCategory` | bool | Wenn `true`, wird bei Fehlerhaften Weiterleitungen nach Möglichkeit auf die Elternkategorie umgeleitet.
    Default: `true` | *** ## `urls.urls` - Allgemeine Einstellungen für SEO-URLs Über den Unterknoten `urls` wird gesteuert, wie sprechende URLs im Shop aufgebaut und bereinigt werden. Dabei wird unter anderem festgelegt, ob die URL-Logik aktiv ist, ob URLs kleingeschrieben werden und welche Trennzeichen verwendet werden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "alwaysEndWithSlash": true, "generate": [ { "options": { "urlschema": [ { "schema": [ { "fields": [ "categoryPath" ], "listOptions": { "categoryField": "name", "order": "reverse", "top": 2 }, "optional": true, "separator": "/", "type": "field" }, { "fields": [ "name" ], "optional": true, "separator": "/", "type": "field" } ], "subshop": "englisch" }, { "schema": [ { "fields": [ "categoryPath" ], "listOptions": { "categoryField": "name", "order": "normal", "top": 1 }, "optional": true, "separator": "/", "type": "field" }, { "fields": [ "name" ], "optional": true, "separator": "/", "type": "field" } ] } ] }, "service": "seoUrlHandler.category" }, { "options": { "urlschema": [ { "schema": [ { "fields": [ "brand" ], "optional": true, "separator": "/", "type": "field" }, { "fields": [ "categoryPath" ], "listOptions": { "categoryField": "name", "order": "normal", "top": 1 }, "optional": true, "separator": "/", "type": "field" }, { "fields": [ "name" ], "optional": true, "separator": "/", "type": "field" } ] } ] }, "service": "seoUrlHandler.product" } ], "lowercase": true, "mappings": { "ß": "ss", "ä": "ae", "ö": "oe", "ü": "ue" }, "parametersToRemove": [ "ref" ], "suffixSeparator": "-", "wordSeparator": "_" } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | -------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `active` | bool | Schaltet die URL-Logik ein/aus. Wenn `false`, wird die automatische SEO-URL-Verarbeitung (Funktion, die die URLs suchmaschinenfreundlich macht) deaktiviert. Default: `true` | | `lowercase` | bool | Wenn `true`, werden URLs in Kleinbuchstaben ausgegeben (z.B. `/produkte/t-shirt`). | | `suffixSeparator` | string | Separator zwischen Basis-URL und Suffix (z.B. Produkt-ID). Häufig z.B. `-` (z.B. `/t-shirt-1234`). | | `wordSeparator` | string | Separator zwischen Wörtern im Pfad, z.B. `_` → `/t_shirt_herren/`) | | `alwaysEndWithSlash` | bool | Wenn `true`, enden generierte URLs immer mit `/` (z.B. `/herren/t-shirts/`) | | `parametersToRemove` | list (string) | Liste von Query-Parametern, die aus URLs entfernt werden sollen (z.B. Tracking-Parameter wie `ref`, `utm`). | | `mappings` | map | Zeichen-Mappings für die URL-Erzeugung.
    Schlüssel = Originalzeichen (meist für Umlaute verwendet), Wert = Ersatzzeichenfolge. | | `` | string | Originalzeichen (z.B. `ä`, `ß`), das in URLs ersetzt werden soll. | | `` | string | Ersatzzeichen (z.B. `ae` statt `ä`), das das Originalzeichen ersetzt. | | `generate` | list (object) | Ein Eintrag in `generate` beschreibt die URL-Erzeugung für einen bestimmten Typ, z.B. Kategorien oder Produkte. | | `service` | string | Name des URL-Handlers, z.B. `seoUrlHandler.category`. | | `options` | object | Optionen für diesen Service, insbesondere die Definition der URL-Schemate über `urlschema`. | | `urlschema` | list (object) | Jedes `urlschema` beschreibt ein Schema für die Zusammensetzung des URL-Pfads. | | `subshop` | string | Subshop-ID, für den dieses Schema gilt (z.B. `englisch`). | | `schema` | list (object) | Liste von Schema Bausteinen, die nacheinander den URL-Pfad aufbauen. | | `type` | string | Art des Schema-Bausteins, z.B. `field`. | | `fields` | list (string) | Liste von Feldnamen, deren Werte in diesen Abschnitt einfließen (z.B. `categoryPath`, `brand`, `name`). | | `separator` | string | Trenner, der hinter diesem Abschnitt in der URL gesetzt wird (z.B. `/` ). | | `optional` | bool | Wenn `true`, wird der Baustein übersprungen, falls keine Werte vorhanden sind. | | `listOptions` | object | Zusätzliche Optionen, wenn das Feld eine Liste/Hierarchie ist (z.B. `categoryPath`). | | `categoryField` | string | Feld, das für den Kategorienamen genutzt wird (typisch: `name`). | | `order` | enum | Reihenfolge, in der Kategorien ausgegeben werden. `normal` - von oben nach unten `reverse` - von unten nach oben | | `top` | int | Anzahl der Ebenen, die übernommen werden sollen (z.B. `1` → nur die oberste Kategorie oder `2` → die ersten beiden Ebenen). | # Validierungs- und Prüfservices Source: https://dokumentation.websale.de/konfiguration/validierungs-und-prufservices Übersicht der WEBSALE-Validierungs- und Prüfservices für Benutzereingaben sowie regelbasierter Prüfungen für Zahlungs- und Versandarten im Shop. Diese Seite beschreibt die verfügbaren Services zur Validierung von Benutzereingaben sowie die regelbasierten Prüfungen für Zahlungs- und Versandarten. Die Services sind keine klassischen Konfigurationsknoten mit eigener Struktur, sondern werden in den jeweiligen Formular- oder Regeldefinitionen referenziert (z. B. in Account-, Checkout- oder Payment-/Shipping-Konfigurationen). *** ## `addressCheck.*` - Adressvalidierungen `addressCheck.*` enthält Prüfungen für Adressfelder (z.B. Name, Straße, PLZ). Die Prüfungen werden in den jeweiligen Felddefinitionen unter `validations` hinterlegt. Das Frontend zeigt die Felder wie konfiguriert an und prüft beim Ausfüllen, ob die Eingaben gültig sind. So werden falsche oder unzulässige Werte früh erkannt. ### `addressCheck.minLength` - Mindestlänge Prüft die Mindestlänge der Eingabe bei Adressfeldern. #### Beispielkonfiguration für (`accounts.addressField.firstName`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "name": "firstName", "validations": [ { "options": { "len": 1 }, "service": "addressCheck.minLength" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------- | | `len` | Gewünschte Mindestlänge in Zahlen. | ### `addressCheck.maxLength` - Maximallänge Prüft die Maximallänge der Eingabe bei Adressfeldern. #### Beispielkonfiguration für (`accounts.addressField.firstName`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "name": "firstName", "validations": [ { "options": { "len": 255 }, "service": "addressCheck.maxLength" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------- | | `len` | Gewünschte Maximallänge in Zahlen. | ### `addressCheck.numeric` - Nur Ziffern Prüft, ob die Eingabe bei Adressfeldern nur aus Ziffern besteht. #### Beispielkonfiguration für (`accounts.addressField.phone`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "name": "phone", "validations": [ { "service": "addressCheck.numeric" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ----------------------------- | | -- | Keine zusätzlichen Parameter. | ### `addressCheck.country` - Ländercode (ISO) Prüft, ob die Eingabe resp. Auswahl bei Länderlisten der Adressdatenfelder ein im Shop konfigurierter Ländercode ist (ISO-Code: 2-stellig, 3-stellig oder ISO-Nummer). Die offiziellen ISO-3166-1-Codes (alpha-2, alpha-3 und numerisch) finden sich auf der Website der International Organization for Standardization (ISO): [https://www.iso.org/iso-3166-country-codes.html](https://www.iso.org/iso-3166-country-codes.html) #### Beispielkonfiguration für (`accounts.addressField.country`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "name": "country", "validations": [ { "service": "addressCheck.country" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ----------------------------- | | -- | Keine zusätzlichen Parameter. | ### `addressCheck.zip` - Postleitzahl (PLZ) Prüft, ob die Eingabe eine gültige Postleitzahl (PLZ) für das angegebene Land ist. Die PLZ-Regeln stammen aus der Konfiguration. Das dazugehörige Land muss zwingend im Feld `country` übergeben werden. #### Beispielkonfiguration für (`accounts.addressField.zip`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "name": "zip", "validations": [ { "service": "addressCheck.zip" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ----------------------------- | | -- | Keine zusätzlichen Parameter. | ### `addressCheck.salutation` - Anrede (Code) Prüft, ob die Eingabe eine gültige Anrede ist (Code gemäß Konfiguration). #### Beispielkonfiguration für (`accounts.addressField.salutationCode`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "name": "salutationCode", "validations": [ { "service": "addressCheck.salutation" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ----------------------------- | | -- | Keine zusätzlichen Parameter. | ### `addressCheck.regex` - Regulärer Ausdruck Prüft, ob die Eingabe zu einem regulären Ausdruck passt. #### Beispielkonfiguration für (`accounts.addressField.additionalInfo`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "name": "additionalInfo", "validations": [ { "options": { "expression": "^((?i)(?!Postfach).)*$" }, "service": "addressCheck.regex" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------- | | `expression` | Regulärer Ausdruck (Zeichenkette). | ### `addressCheck.phone` - Telefonnummer Prüft, ob die Eingabe eine gültige Telefonnummer ist. Eine gültige Nummer besteht aus Ziffern (ohne Längenbeschränkung) und optional einer internationalen Vorwahl. Das `+` in der Vorwahl wird **nach** erfolgreicher Validierung durch `00` ersetzt. #### Beispielkonfiguration für (`accounts.addressField.phone`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "name": "phone", "validations": [ { "service": "addressCheck.phone" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ----------------------------- | | -- | Keine zusätzlichen Parameter. | ### `addressCheck.alpha` - Nur Buchstaben (A–Z) Prüft, ob die Eingabe nur aus lateinischen Buchstaben besteht (Groß-/Kleinschreibung egal). #### Beispielkonfiguration für (`accounts.addressField.additionalInfo`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "name": "additionalInfo", "validations": [ { "service": "addressCheck.alpha" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ----------------------------- | | -- | Keine zusätzlichen Parameter. | ### `addressCheck.alphanum` - Buchstaben/Ziffern (A–Z/0–9) Prüft, ob die Eingabe nur aus lateinischen Buchstaben oder Ziffern besteht (Groß-/Kleinschreibung egal). #### Beispielkonfiguration für (`accounts.addressField.additionalInfo`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "name": "additionalInfo", "validations": [ { "service": "addressCheck.alphanum" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ----------------------------- | | -- | Keine zusätzlichen Parameter. | ### `addressCheck.legalSigns` - Erlaubte Zeichen Prüft, ob alle Zeichen der Eingabe in der erlaubten Zeichenauswahl enthalten sind (Groß-/Kleinschreibung relevant). #### Beispielkonfiguration für (`accounts.addressField.additionalInfo`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "name": "additionalInfo", "validations": [ { "options": { "signs": "123456ABCSDEF" }, "service": "addressCheck.legalSigns" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | -------------------------------- | | `signs` | Erlaubte Zeichen (Zeichenkette). | ### `addressCheck.illegalSigns` - Verbotene Zeichen Gegenteil von `legalSigns`: Die Eingabe darf keines der angegebenen Zeichen enthalten. #### Beispielkonfiguration für (`accounts.addressField.phone`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "name": "phone", "validations": [ { "options": { "signs": "*|~%${};\"<>§@()/-_#" }, "service": "addressCheck.illegalSigns" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------- | | `signs` | Unerlaubte Zeichen (Zeichenkette). | ### `addressCheck.date` - Datum Prüft, ob die Eingabe ein gültiges Datum ist, und formatiert die Eingabe bei Bedarf. #### Beispielkonfiguration für (`accounts.addressField.additionalInfo`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "name": "additionalInfo", "validations": [ { "options": { "delimiter": "-", "dateformat": "DMY", "formatleadingzero": false }, "service": "addressCheck.date" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `delimiter` | Trennzeichen zwischen Tag/Monat/Jahr (z. B. `-` für `15-10-2025`). | | `dateformat` | Beliebige Kombination aus `D`, `M`, `Y` (z. B. `DMY` für `15-10-2025`). | | `formatleadingzero` | Wenn aktiv (`true`), werden Tage/Monate zweistellig formatiert (`5 → 05`).
    Wenn deaktiviert (`false`), werden führende Nullen entfernt (`05 → 5`). (Wahrheitswert) | ### `addressCheck.allowedSelection` - Auswahl (Listenelement) Validiert, ob die Eingabe einem vordefinierten Auswahlwert entspricht. Die zulässigen Werte stammen aus einer [Adressliste](/konfiguration/general-allgemeine-shopeinstellungen#general-addresslistelements-adresslisten) unter `general.addressListElements`, die über `listElements` referenziert wird. Typische Anwendung: Prüfung, ob eine Adresse z. B. „Packstation" oder „Privatadresse" ist. #### Beispielkonfiguration für (`accounts.addressField.addressType`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "name": "addressType", "validations": [ { "options": { "listElements": "billAddressType" }, "service": "addressCheck.allowedSelection" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `listElements` | Referenz auf die Adressliste, deren Werte zulässig sind.
    Zulässig ist die `dataId` der Liste (z. B. `billAddressType`) **oder** der vollständige Knotenpfad (z. B. `general.addressListElements.billAddressType`). Beide Schreibweisen sind gleichwertig. | **Zusammenspiel mit dem `addressType` der Liste** Ob die Prüfung überhaupt greift, hängt vom Parameter `addressType` der referenzierten Liste ab: | **`addressType` der Liste** | **Prüfung bei Rechnungsadresse** | **Prüfung bei Lieferadresse** | **Prüfung ohne Adresstyp-Kontext** | | --------------------------- | -------------------------------- | ----------------------------- | ---------------------------------- | | `"bill"` | greift | greift nicht | greift nicht | | `"delivery"` | greift nicht | greift | greift nicht | | `"both"` | greift | greift | greift | | nicht gesetzt | greift | greift | greift nicht | Greift die Prüfung nicht, wird das Feld ohne Fehler akzeptiert, die Validierung fällt also stillschweigend aus, statt die Eingabe abzulehnen. Dasselbe gilt, wenn unter `listElements` eine ID referenziert wird, zu der keine Adressliste existiert (z. B. nach einem Tippfehler oder nach dem Löschen der Liste). Prüfen Sie deshalb bei einem Feld, das unerwartet beliebige Werte annimmt, zuerst die Schreibweise der Referenz und den `addressType` der Liste. **Weiterführend** * [`general.addressListElements`](/konfiguration/general-allgemeine-shopeinstellungen#general-addresslistelements-adresslisten) – Definition der Listen und ihrer zulässigen Werte. * [\$wsConfig.listElements](/frontend/referenz/module/wsconfig#wsconfig-listelements) – Ausgabe derselben Liste als Auswahlfeld im Formular. *** ## `dataChecker.*` - Allgemeine Feldvalidierungen `dataChecker.*` enthält Prüfungen für allgemeine Formularfelder, die nicht speziell zu einer Adresse gehören. Die Prüfungen werden in der jeweiligen Felddefinition unter `validations` eingebunden. Das Frontend übernimmt die Vorgaben aus der Felddefinition und prüft beim Ausfüllen, ob die Eingabe korrekt ist (z.B. Länge, Format oder unerlaubte Zeichen). ### `dataChecker.minLength` - Mindestlänge Prüft die Mindestlänge der Eingaben bei Formular-Eingabefeldern. #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.firstName`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Vorname", "name": "firstName", "required": true, "validations": [ { "options": { "len": 3 }, "service": "dataChecker.minLength" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------- | | `len` | Gewünschte Mindestlänge in Zahlen. | ### `dataChecker.maxLength` - Maximallänge Prüft die Maximallänge der Eingaben bei Formular-Eingabefeldern. #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.firstName`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Vorname", "name": "firstName", "required": true, "validations": [ { "options": { "len": 255 }, "service": "dataChecker.maxLength" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------- | | `len` | Gewünschte Maximallänge in Zahlen. | ### `dataChecker.numeric` - Nur Ziffern Prüft, ob die Eingabe bei Formular-Eingabefeldern nur aus Ziffern besteht. #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.phone`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Telefon", "name": "phone", "validations": [ { "service": "dataChecker.numeric" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ----------------------------- | | -- | Keine zusätzlichen Parameter. | ### `dataChecker.country` - Ländercode (ISO) Prüft, ob die Eingabe resp. Auswahl bei Länderlisten der Formularfelder ein im Shop konfigurierter Ländercode ist (ISO-Code: 2-stellig, 3-stellig oder ISO-Nummer). Die offiziellen ISO-3166-1-Codes (alpha-2, alpha-3 und numerisch) finden sich auf der Website der International Organization for Standardization (ISO): [https://www.iso.org/iso-3166-country-codes.html](https://www.iso.org/iso-3166-country-codes.html) #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.country`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Land", "name": "country", "validations": [ { "service": "dataChecker.country" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ----------------------------- | | -- | Keine zusätzlichen Parameter. | ### `dataChecker.zip` - Postleitzahl (PLZ) Prüft, ob die Eingabe eine gültige Postleitzahl (PLZ) für das angegebene Land ist. Die PLZ-Regeln stammen aus der Konfiguration. Das dazugehörige Land muss zwingend im Feld `country` übergeben werden. #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.zip`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Postleitzahl", "name": "zip", "validations": [ { "service": "dataChecker.zip" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------------------------------------------------------------------------------------------- | | -- | Keine zusätzlichen Parameter.
    (Für länderspezifische Prüfung muss das Feld `country` im Kontext verfügbar sein.) | ### `dataChecker.salutation` - Anrede (Code) Prüft, ob die Eingabe eine gültige Anrede ist (Code gemäß Konfiguration). #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.salutation`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Anrede", "name": "salutation", "validations": [ { "service": "dataChecker.salutation" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ----------------------------- | | -- | Keine zusätzlichen Parameter. | ### `dataChecker.regex` - Regulärer Ausdruck Prüft, ob die Eingabe zu einem regulären Ausdruck passt. #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.additionalInfo`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Zusatzinformation", "name": "additionalInfo", "validations": [ { "options": { "expression": "^((?i)(?!Postfach).)*$" }, "service": "dataChecker.regex" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------- | | `expression` | Regulärer Ausdruck (Zeichenkette). | ### `dataChecker.email` - E‑Mail-Adresse Prüft, ob die Eingabe eine gültige E‑Mail-Adresse ist. #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.mail`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "E-Mail-Adresse", "name": "mail", "validations": [ { "service": "dataChecker.email" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ----------------------------- | | -- | Keine zusätzlichen Parameter. | ### `dataChecker.alphaClass` - Buchstaben (min/verschiedene) Stellt sicher, dass die Eingabe **mindestens** `minChars` lateinische Buchstaben enthält (Groß-/Kleinschreibung egal); optional Mindestanzahl unterschiedlicher Buchstaben. #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.additionalInfo`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Zusatzinformation", "name": "additionalInfo", "required": true, "validations": [ { "options": { "minChars": 8, "minDifferentChars": 2 }, "service": "dataChecker.alphaClass" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------------- | ------------------------------------------------------ | | `minChars` | Mindestanzahl an Buchstaben (Zahl ≥ 0). | | `minDifferentChars` | Mindestanzahl unterschiedlicher Buchstaben (Zahl ≥ 0). | ### `dataChecker.lowerAlphaClass` - Kleinbuchstaben Wie `alphaClass`, jedoch **nur** Kleinbuchstaben. #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.additionalInfo`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Zusatzinformation", "name": "additionalInfo", "required": true, "validations": [ { "options": { "minChars": 8, "minDifferentChars": 2 }, "service": "dataChecker.lowerAlphaClass" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------------- | ----------------------------------------------------------- | | `minChars` | Mindestanzahl an Kleinbuchstaben (Zahl ≥ 0). | | `minDifferentChars` | Mindestanzahl unterschiedlicher Kleinbuchstaben (Zahl ≥ 0). | ### `dataChecker.upperAlphaClass` - Großbuchstaben Wie `alphaClass`, jedoch **nur** Großbuchstaben. #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.additionalInfo`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Zusatzinformation", "name": "additionalInfo", "required": true, "validations": [ { "options": { "minChars": 8, "minDifferentChars": 2 }, "service": "dataChecker.upperAlphaClass" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------------- | ---------------------------------------------------------- | | `minChars` | Mindestanzahl an Großbuchstaben (Zahl ≥ 0). | | `minDifferentChars` | Mindestanzahl unterschiedlicher Großbuchstaben (Zahl ≥ 0). | ### `dataChecker.digitClass` - Ziffern Wie `alphaClass`, jedoch für Ziffern. #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.additionalInfo`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Zusatzinformation", "name": "additionalInfo", "required": true, "validations": [ { "options": { "minChars": 4, "minDifferentChars": 2 }, "service": "dataChecker.digitClass" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------------- | --------------------------------------------------- | | `minChars` | Mindestanzahl an Ziffern (Zahl ≥ 0). | | `minDifferentChars` | Mindestanzahl unterschiedlicher Ziffern (Zahl ≥ 0). | ### `dataChecker.specialClass` - Sonderzeichen Wie `alphaClass`, jedoch für Sonderzeichen. #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.additionalInfo`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Zusatzinformation", "name": "additionalInfo", "required": true, "validations": [ { "options": { "minChars": 2, "minDifferentChars": 1 }, "service": "dataChecker.specialClass" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------------- | --------------------------------------------------------- | | `minChars` | Mindestanzahl an Sonderzeichen (Zahl ≥ 0). | | `minDifferentChars` | Mindestanzahl unterschiedlicher Sonderzeichen (Zahl ≥ 0). | ### `dataChecker.sequenceOfIdenticalCharacters` - Wiederholte Zeichen (Sequenz) Prüft, ob dasselbe Zeichen zu oft hintereinander vorkommt. #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.additionalInfo`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Zusatzinformation", "name": "additionalInfo", "required": true, "validations": [ { "options": { "caseInsensitive": false, "maxSequence": 2 }, "service": "dataChecker.sequenceOfIdenticalCharacters" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ----------------- | --------------------------------------------------------- | | `caseInsensitive` | Groß-/Kleinschreibung ignorieren (Wahrheitswert). | | `maxSequence` | Maximale erlaubte Wiederholung eines Zeichens (Zahl ≥ 0). | ### `dataChecker.consecutiveNumbers` - Fortlaufende Zahlen Prüft auf auf- oder absteigende Zahlenketten (z. B. `12345` oder `54321`). #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.additionalInfo`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Zusatzinformation", "name": "additionalInfo", "required": true, "validations": [ { "options": { "maxConsecutive": 2 }, "service": "dataChecker.consecutiveNumbers" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ---------------- | ------------------------------------------ | | `maxConsecutive` | Maximale Länge der Zahlenkette (Zahl ≥ 0). | ### `dataChecker.consecutiveLetters` - Fortlaufende Buchstaben Prüft auf auf- oder absteigende Buchstabenkombinationen (z. B. `abcd` oder `dcba`). #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.additionalInfo`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Zusatzinformation", "name": "additionalInfo", "required": true, "validations": [ { "options": { "maxConsecutive": 2, "caseInsensitive": false }, "service": "dataChecker.consecutiveLetters" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ----------------- | ------------------------------------------------- | | `maxConsecutive` | Maximale Länge der Buchstabenkette (Zahl ≥ 0). | | `caseInsensitive` | Groß-/Kleinschreibung ignorieren (Wahrheitswert). | ### `dataChecker.palindrome` - Palindrom Prüft, ob die Eingabe ein Palindrom ist (vorwärts/rückwärts identisch, z. B. „Otto"). #### Beispielkonfiguration für (`inquiry.form.catalogue.fields.additionalInfo`) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Zusatzinformation", "name": "additionalInfo", "required": true, "validations": [ { "options": { "caseInsensitive": false }, "service": "dataChecker.palindrome" } ] } ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ----------------- | ------------------------------------------------- | | `caseInsensitive` | Groß-/Kleinschreibung ignorieren (Wahrheitswert). | *** ## `paymentValidation.*` - Zahlungsarten-Validierung `paymentValidation.*` enthält Regeln, mit denen festgelegt wird, ob eine Zahlungsart im Checkout erlaubt ist. Die Prüfung kann z.B. vom Land der Rechnungs- oder Lieferadresse, vom Kundentyp, vom Warenkorb oder vom Bestellwert abhängen. Diese Regeln können in der Konfiguration der jeweiligen Zahlungsart unter `validations` eingetragen werden. Das Frontend zeigt dann nur passende Zahlungsarten an oder verhindert die Auswahl, wenn die Bedingungen nicht erfüllt sind. Hier geht es zum zugehörigen Konfigurationsknoten `payment`: [payment - Zahlungsmethoden](/konfiguration/payment-zahlungsmethoden) **Auswertung im Frontend** Im Template werden die konfigurierten Regeln über die Methode [`$wsCheckout.isValidPayment(paymentId)`](/frontend/referenz/module/wscheckout#wscheckout-isvalidpayment) ausgewertet: Sie führt alle unter `validations` hinterlegten Services aus und gibt `false` zurück, sobald mindestens eine Regel fehlschlägt. So werden nicht verfügbare Zahlungsarten in der Auswahl deaktiviert oder ausgeblendet. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $cPayment in $wsConfig.payments }} {{ /foreach }} ``` Für die aktuell ausgewählte Zahlungsart stehen die Gründe einer fehlgeschlagenen Prüfung unter [`$wsCheckout.problems.payment`](/frontend/referenz/module/wscheckout#wscheckout-problems-payment) bereit; das Feld `check` nennt den fehlgeschlagenen Service. ### `paymentValidation.billCountry` - Validierung des Landes (Rechnungsadresse) für Zahlungsarten Prüft, ob das Land der Rechnungsadresse entsprechend einer „Allow/Deny"-Liste für eine Zahlungsart zulässig ist. Über die Optionen kann festgelegt werden, für welche Länder die Regel greift und ob diese Liste Länder erlaubt oder verbietet. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "options": { "countryList": [ "general.country.de", "general.country.at", "general.country.ch" ], "rule": "allow" }, "service": "paymentValidation.billCountry" } ] ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `countryList` | Liste der Länder, auf die diese Regel angewendet werden soll.
    (ISO-Länderkennungen, z.B. „`DE`", „`AT`", „`CH`") | | `rule` | Steuerung der Regel.
    Mögliche Werte:
    - `allow` - Länder, die in `countryList` stehen, sind erlaubt.
    - `deny` - Länder, die in `countryList` stehen, sind nicht erlaubt. | ### `paymentValidation.billPhone` - Validierung der Telefonnummer Prüft, ob für die Rechnungsadresse eine Telefonnummer angegeben ist (das Feld darf nicht leer sein). #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "service": "paymentValidation.billPhone" } ] ``` Für diesen Service sind keine Parameter vorhanden. ### `paymentValidation.billDateOfBirth` - Validierung des Geburtsdatums Prüft, ob für die Rechnungsadresse ein Geburtsdatum angegeben ist (das Feld darf nicht leer sein). #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "service": "paymentValidation.billDateOfBirth" } ] ``` Für diesen Service sind keine Parameter vorhanden. ### `paymentValidation.shippingCountry` - Validierung des Landes (Lieferadresse) Prüft, ob das Land der Lieferadresse entsprechend einer „Allow/Deny"-Liste zulässig ist. Über die Optionen kann festgelegt werden, für welche Länder die Regel greift und ob diese Liste Länder erlaubt oder verbietet. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "options": { "countryList": [ "general.country.gb" ], "rule": "deny" }, "service": "paymentValidation.shippingCountry" } ] ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `countryList` | Liste der Länder, auf die diese Regel angewendet werden soll.
    (ISO-Länderkennungen, z.B. „`DE`", „`AT`", „`CH`") | | `rule` | Steuerung der Regel.
    Mögliche Werte:
    - `allow` - Länder, die in `countryList` stehen, sind erlaubt.
    - `deny` - Länder, die in `countryList` stehen, sind nicht erlaubt. | ### `paymentValidation.shippingMethod` - Validierung der Versandart für Zahlungsarten Prüft, ob die gewählte Zahlart nur mit bestimmten Versandarten verwendet werden darf. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "options": { "shippingMethods": [ "shipping.method.dhl", "shipping.method.pickup" ], "rule": "allow" }, "service": "paymentValidation.shippingMethod" } ] ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `shippingMethods` | Liste der Versandarten-IDs, auf die diese Regel angewendet werden soll.
    Die IDs entsprechen den internen Namen der Versandarten (z.B. `shipping.method.dhl`). | | `rule` | Steuerung der Regel.
    Mögliche Werte:
    - `allow` - Versandarten, die in `shippingMethods` stehen, sind erlaubt.
    - `deny` - Versandarten, die in `shippingMethods` stehen, sind nicht erlaubt. | ### `paymentValidation.accountType` - Validierung des Kundentyps für Zahlungsarten Prüft, ob die gewählte Zahlart nur für bestimmte Kundentypen verwendet werden darf (Gast, Neukunde oder Bestandskunde). #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "options": { "deny": [ "guest", "newCustomer" ] }, "service": "paymentValidation.accountType" } ] ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `deny` | Liste an Kundentypen, für die die Zahlart gesperrt ist.
    Mögliche Werte:
    - „`guest`" - Gastbesteller
    - „`newCustomer`" - Neukunde
    - „`customer`" - Bestandskunde | **Wie der Kundentyp ermittelt wird** * `guest` - Der Kunde bestellt als Gast (ohne Benutzerkonto). * `newCustomer` - Ein eingeloggter Kunde, der beim Login die in [`accounts.account.newCustomerRules`](/konfiguration/accounts-benutzerkonten#neukunden-regeln-newcustomerrules) konfigurierten Neukunden-Regeln erfüllt. Eine Neuregistrierung im Bestellablauf führt unabhängig von den Regeln immer zum Typ `newCustomer`. * `customer` - Jeder andere eingeloggte Kunde. Sind keine Neukunden-Regeln konfiguriert, gelten eingeloggte Kunden immer als `customer`. Der hier geprüfte Kundentyp ist nicht identisch mit der Template-Variable [`$wsCheckout.accountType`](/frontend/referenz/module/wscheckout#wscheckout-accounttype) (`guest` / `new` / `registered`): Diese gibt die im Bestellablauf gewählte Anmeldemethode aus, während die Validierung zwischen Neu- und Bestandskunden (`newCustomer` / `customer`) unterscheidet. In den Bestelldaten werden `customer` und `newCustomer` beide als `registered` ausgegeben. ### `paymentValidation.denyDifferingShippingAddress` - Validierung abweichender Lieferadressen für Zahlungsarten Prüft, ob Rechnungsadresse und Lieferadresse identisch sind.
    Die Zahlart ist nur erlaubt, wenn keine abweichende Lieferadresse verwendet wird. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "service": "paymentValidation.denyDifferingShippingAddress" } ] ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ----------------------------- | | -- | Keine zusätzlichen Parameter. | ### `paymentValidation.voucherDeny` - Validierung von Gutscheinprodukten für Zahlungsarten Prüft, ob Gutscheinprodukte im Warenkorb sind. Wenn Gutscheinprodukte im Warenkorb sind, ist diese Zahlart nicht erlaubt. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "service": "paymentValidation.voucherDeny" } ] ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ----------------------------- | | -- | Keine zusätzlichen Parameter. | ### `paymentValidation.total` - Validierung von Mindest- / Maximalbestellwert für Zahlungsarten Prüft, ob die Zahlart nur verwendet werden darf, wenn ein bestimmter Mindest- oder Maximalbestellwert erreicht bzw. überschritten wird. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "options": { "total": 600, "type": "max" }, "service": "paymentValidation.total" } ] ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `total` | Grenzwert der Gesamtsumme (Warenwert), ab bzw. bis zu der die Zahlart erlaubt ist. | | `type` | Art der Prüfung.
    Mögliche Werte:
    - „`min`" - Die Zahlart ist nur erlaubt, wenn der Bestellwert mindestens `total` erreicht.
    - „`max`" - Die Zahlart ist nur erlaubt, wenn der Bestellwert `total` nicht überschreitet. | Wenn Mindest- und Maximalbestellwert gleichzeitig geprüft werden sollen, muss diese Prüfung zweimal mit unterschiedlichen Optionen konfiguriert werden. ### `paymentValidation.inventoryState` - Validierung des Lagerbestandes für Zahlungsarten Prüft, ob sich im Warenkorb Produkte mit einem bestimmten Lagerbestand befinden. Wenn ein Produkt im Warenkorb einen in `deny` konfigurierten Status hat, ist die Zahlungsart nicht erlaubt. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "options": { "deny": [ "red", "yellow" ] }, "service": "paymentValidation.inventoryState" } ] ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `deny` | Liste an Lagerbestandsdaten, bei denen die Zahlungsart verboten ist.
    Mögliche Werte:
    - „`red`" - ausverkauft
    - „`yellow`" - nur noch wenige vorhanden
    - „`green`" - viele vorhanden
    Die Grenzwerte der einzelnen Lagerbestände werden in `content.inventory` festgelegt: [content - Katalog (Kategorien & Produkte)](/konfiguration/content-katalog-kategorien-produkte) | ### `paymentValidation.productDependency` - Validierung der Produkt-Abhängigkeiten für Zahlungsarten Prüft die Produkte im Warenkorb anhand der Konfiguration [checkout.productDependency](/konfiguration/checkout-bestellablauf#checkout-productdependency-produktabhängigkeiten).
    Eine Zahlungsart wird nur angeboten, wenn alle referenzierten Produktabhängigkeiten erfüllt sind. Auf diese Weise koppeln Sie eine Zahlungsart an Warenkorb-Eigenschaften, ohne die Prüflogik zu duplizieren. Die eigentlichen Bedingungen (Produktfelder, Freifelder, Wertevergleiche) werden zentral in [checkout.productDependency](/konfiguration/checkout-bestellablauf#checkout-productdependency-produktabhängigkeiten) gepflegt. #### Beispielkonfiguration Die Option "Kauf auf Rechnung" soll gesperrt werden, sobald sich ein personalisiertes Produkt (z.B. mit Gravur) im Warenkorb befindet. Weil personalisierte Artikel nicht retournierbar sind, tragen sie ein höheres Zahlungsausfallrisiko. Die Bedingung "keine Gravur im Warenkorb" definieren Sie in [checkout.productDependency](/konfiguration/checkout-bestellablauf#checkout-productdependency-produktabhängigkeiten) und referenzieren sie anschließend hier. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "options": { "list": [ "checkout.productDependency.noEngraving" ] }, "service": "paymentValidation.productDependency" } ] ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `list` | Liste mit IDs der Konfigurationen aus [checkout.productDependency](/konfiguration/checkout-bestellablauf#checkout-productdependency-produktabhängigkeiten), die geprüft werden sollen.
    Damit die Validierung erfolgreich ist und die Zahlungsart angeboten wird, müssen alle hier angegebenen Werte erfüllt sein. | ### `paymentValidation.userAgent` - Validierung des User-Agents für Zahlungsarten Prüft, ob eine Zahlungsart basierend auf dem genutzten Gerät oder Browser des Kunden angezeigt wird. Geräte und Browser übermitteln beim Seitenaufruf automatisch eine technische Kennung, den sogenannten User-Agent. Anhand dieser Kennung lässt sich z.B. erkennen, ob jemand ein iPhone, ein iPad oder einen Mac verwendet. Die in `userAgents` eingetragenen Begriffe werden gegen diese Kennung geprüft, ein Treffer genügt. So lässt sich eine Zahlungsart gezielt nur für bestimmte Geräte oder Browser freischalten oder sperren, z.B. wenn Apple Pay nur für Kunden angezeigt werden soll, die ein Apple-Gerät oder einen kompatiblen Browser verwenden. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "options": { "userAgents": [ "Macintosh", "Mac OS X", "iPhone", "iPad" ], "rule": "allow" }, "service": "paymentValidation.userAgent" } ] ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `userAgents` | Liste von Begriffen, die in der Gerät-/Browser-Kennung des Kunden gesucht werden.
    Ein Treffer genügt.
    Die Werte sind nicht durch WEBSALE vorgegeben, sondern entsprechen den tatsächlichen Zeichenketten, die das jeweilige Gerät oder der Browser übermittelt.
    Die korrekten Werte müssen selbst am jeweiligen Gerät ermittelt werden, z.B. über die Browser-Konsole. | | `rule` | Steuerung der Regel.
    Mögliche Werte:
    - `allow` - Zahlart wird nur angezeigt, wenn mindestens ein Begriff aus `userAgents` erkannt wird.
    - `deny` - Zahlart wird ausgeblendet, wenn ein Treffer gefunden wird. | *** ## `shippingMethodValidation.*` - Versandarten-Validierung `shippingMethodValidation.*` enthält Regeln, mit denen festgelegt wird, ob eine Versandart im Checkout erlaubt ist. Die Prüfung kann z.B. vom Lieferland, vom Warenwert, von Produkttypen oder von der gewählten Zahlungsart abhängen. Diese Regeln können in der Konfiguration der jeweiligen Versandart unter `validations` eingetragen werden. Das Frontend stellt dann nur die Versandarten bereit, die zu den aktuellen Bedingungen passen. **Auswertung im Frontend** Im Template werden die konfigurierten Regeln über die Methode [`$wsCheckout.isValidShippingMethod(shippingMethodId)`](/frontend/referenz/module/wscheckout#wscheckout-isvalidshippingmethod) ausgewertet (gleiches Muster wie bei den Zahlungsarten). Die Gründe für eine deaktivierte Versandart lassen sich zusätzlich über [`$wsCheckout.getShippingMethodDisabledErrors(shippingMethodId)`](/frontend/referenz/module/wscheckout#wscheckout-getshippingmethoddisablederrors) ausgeben. ### `shippingMethodValidation.shippingCountry` - Validierung des Landes (Lieferadresse) Prüft, ob das Land der Lieferadresse entsprechend einer „Allow/Deny"-Liste zulässig ist. Über die Optionen kann festgelegt werden, für welche Länder die Regel greift und ob diese Liste Länder erlaubt oder verbietet. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "options": { "countryList": [ "general.country.de", "general.country.at" ], "rule": "allow" }, "service": "shippingMethodValidation.shippingCountry" } ] ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `countryList` | Liste der Länder, auf die diese Regel angewendet werden soll.
    (ISO-Länderkennungen, z.B. „`DE`", „`AT`", „`CH`") | | `rule` | Steuerung der Regel.
    Mögliche Werte:
    - `allow` - Länder, die in `countryList` stehen, sind erlaubt.
    - `deny` - Länder, die in `countryList` stehen, sind nicht erlaubt. | ### `shippingMethodValidation.paymentMethod` - Validierung der Zahlungsart für Versandarten Prüft, ob eine Versandart nur mit bestimmten Zahlungsarten verwendet werden darf. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "options": { "paymentMethods": [ "payment.method.invoice", "payment.method.prepayment" ], "rule": "allow" }, "service": "shippingMethodValidation.paymentMethod" } ] ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `paymentMethods` | Liste der Zahlungsarten-IDs, die auf diese Regel angewendet werden.
    Die IDs entsprechen den internen Namen der Zahlungsarten (z.B. `payment.method.invoice`) | | `rule` | Steuerung der Regel.
    Mögliche Werte:
    - `allow` - Zahlungsarten, die in `paymentMethods` stehen, sind erlaubt.
    - `deny` - Zahlungsarten, die in `paymentMethods` stehen, sind nicht erlaubt. | ### `shippingMethodValidation.valueOfGoods` - Validierung des Mindest-/Maximalbestellwerts für Versandarten Prüft, ob die Versandart nur verwendet werden darf, wenn ein bestimmter Mindest- oder Maximalbestellwert erreicht bzw. überschritten wird. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "options": { "valueOfGoods": 100, "type": "min" }, "service": "shippingMethodValidation.valueOfGoods" } ] ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `valueOfGoods` | Grenzwert der Gesamtsumme (Warenwert), ab bzw. bis zu der die Versandart erlaubt ist. | | `type` | Art der Prüfung.
    Mögliche Werte:
    - „`min`" - Die Versandart ist nur erlaubt, wenn der Bestellwert mindestens `valueOfGoods` erreicht.
    - „`max`" - Die Versandart ist nur erlaubt, wenn der Bestellwert `valueOfGoods` nicht überschreitet. | ### `shippingMethodValidation.productType` - Validierung des Produkttyps für Versandarten Prüft, ob alle Produkte im Warenkorb einen passenden Produkttyp haben. #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "options": { "rule": "allow", "ruleList": [ "productType.digital" ], "includeList": [ "productType.service" ] }, "service": "shippingMethodValidation.productType" } ] ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `rule` | Art der Prüfung.
    Mögliche Werte:
    - „`allow`" - Nur Produkttypen aus `ruleList` und `includeList` sind erlaubt.
    - „`deny`" - Produkttypen aus `ruleList` sind nicht erlaubt. Ausnahme: Produkttypen aus `includeList` sind immer erlaubt. | | `ruleList` | Liste der Produkttypen, die - abhängig von `rule` - erlaubt oder nicht erlaubt sind. | | `includeList` | Liste der Produkttypen, die immer erlaubt sind. | ### `shippingMethodValidation.productDependency` - Validierung der Produkt-Abhängigkeiten für Versandarten Prüft die Produkte im Warenkorb anhand der Konfiguration [checkout.productDependency](/konfiguration/checkout-bestellablauf#checkout-productdependency-produktabhängigkeiten). #### Beispielkonfiguration ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "options": { "list": [ "checkout.productDependency.digitalOnly", "checkout.productDependency.noBulkyGoods" ] }, "service": "shippingMethodValidation.productDependency" } ] ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `list` | Liste mit IDs der Konfigurationen aus `checkout.productDependency`, die geprüft werden sollen.
    Damit die Validierung erfolgreich ist, müssen alle hier angegebenen Werte erfüllt sein. | ### `shippingMethodValidation.expressCheckout` - Validierung des Express-Checkout für Versandarten Prüft, ob eine Versandart abhängig von der im Express-Checkout verwendeten Zahlungsart erlaubt ist. Die Prüfung greift bei PayPal Express sowie Apple Pay und Google Pay Express (PayPal Commerce Platform). #### Beispielkonfiguration Die Versandart soll nicht wählbar sein, wenn der Kunde den Bestellvorgang als PayPal-Express-Checkout durchläuft: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "validations": [ { "options": { "rule": "deny", "ruleList": [ "paypalCheckout" ] }, "service": "shippingMethodValidation.expressCheckout" } ] ``` #### Parameterübersicht | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `rule` | Art der Prüfung.
    Mögliche Werte:
    - „`deny`" - Läuft der Bestellvorgang als Express-Checkout mit einer Zahlungsart aus `ruleList`, ist die Versandart gesperrt. Außerhalb des Express-Checkouts ist die Versandart erlaubt.
    - „`allow`" - Die Versandart ist **nur** erlaubt, wenn der Bestellvorgang als Express-Checkout mit einer Zahlungsart aus `ruleList` läuft. Im normalen Checkout (kein Express-Checkout aktiv) ist die Versandart damit immer gesperrt - `allow` definiert also eine reine Express-Checkout-Versandart. | | `ruleList` | Liste der Zahlungsarten-IDs, die - abhängig von `rule` - im Express-Checkout erlaubt bzw. verboten sind.
    Die IDs entsprechen den Kennungen der Zahlarten aus [payment.payment](/konfiguration/payment-zahlungsmethoden) (z.B. `paypalCheckout`). | Schlägt die Prüfung fehl, liefert die Validierung den Fehler `expressCheckoutDenied` bzw. `expressCheckoutNotAllowed`; im Frontend lässt er sich über [`$wsCheckout.getShippingMethodDisabledErrors()`](/frontend/referenz/module/wscheckout#wscheckout-getshippingmethoddisablederrors) ausgeben. # Schnittstellen Source: https://dokumentation.websale.de/schnittstellen Schnittstellen von WEBSALE: Admin Interface API, Storefront API, Search API, ASSE und externe Datei-Schnittstelle für Drittsystem-Integrationen. Die Schnittstellen des WEBSALE-Shopsystems ermöglichen die Integration externer Systeme und Anwendungen mit dem Shopsystem. Sie bilden die technische Grundlage für den Datenaustausch zwischen Frontend, Backend und angebundenen Drittsystemen wie ERP-, CRM- oder Warenwirtschaftslösungen. Diese Dokumentation richtet sich an Entwicklerinnen und Entwickler, Systemintegratoren sowie technische Partner, die eine Verbindung zu WEBSALE herstellen oder bestehende Datenflüsse automatisieren möchten. Grundlegende Kenntnisse in REST-APIs, HTTP-Requests und JSON werden vorausgesetzt. Von Vorteil sind Erfahrungen im Umgang mit Authentifizierungsverfahren (z. B. OAuth) und Webhooks. Die Dokumentation unterscheidet folgende Hauptbereiche: ## Admin Interface API Die Admin Interface API (REST API des Adminbereichs) ermöglicht den automatisierten Zugriff auf Verwaltungs- und Systemfunktionen des Shops.  Sie dient ausschließlich zur Kommunikation mit dem Administrations-Backend des Shops und unterstützt Abläufe wie Bestellabruf, Kundendatenverwaltung oder Statusaktualisierungen und richtet sich an technische Integrationen und Schnittstellenlösungen, die Daten aus dem Backend lesen oder dort verarbeiten, synchronisieren oder administrieren – beispielsweise für Warenwirtschaft, ERP, CRM oder andere externe Systeme. Diese API ist nicht für den Aufbau oder Betrieb einer Storefront geeignet. → [Zu den Endpunkten der Admin Interface API](/schnittstellen/admin-interface-api) ## Storefront API Die Storefront API dient zur Anbindung von Frontends (z. B. Headless-Storefronts, Progressive Web Apps, Mobile Apps etc.) an das WEBSALE-Shopsystem. Über diese API werden Daten und Funktionen bereitgestellt, die für den Aufbau und Betrieb der sichtbaren Shopoberfläche benötigt werden – etwa Produktdaten, Warenkorbaktionen, Kundenkonten oder Bestellprozesse etc. → [Zu den Endpunkten der Storefront API](/schnittstellen/storefront-api) ## Search API Die Search API stellt den HTTPS-basierten Zugriff auf das versionsunabhängige Suchmodul WEBSALE Search bereit. → [Zu den Endpunkten der Search API](/schnittstellen/search-api) ## ASSE-Schnittstelle (Server-Side-Events) Über die ASSE-Schnittstelle (Asynchronous-Server-Side-Events) können beliebige Daten aus dem Shop asynchron per HTTPS an externe Systeme übermittelt werden (z. B. Newsletter-, Such- oder Tracking-Dienste). Die Übertragung erfolgt serverseitig (Shop-Server → Empfänger-Server) und unabhängig vom Client. → [Zur ASSE-Schnittstelle](/schnittstellen/asse-schnittstelle-server-side-events) ## Externe Datenschnittstelle (Datei-/Bucket-basiert) Über die externe Datenschnittstelle können zusätzliche Inhalte und Zusatzdaten (z. B. erweiterte Produkt-/Kategorieinformationen oder CMS-Inhalte) in die WEBSALE Storefront eingebunden werden. [→ Zur externen Datenschnittstelle](/schnittstellen/externe-datenschnittstelle-datei-bucket-basiert) # Admin Interface API Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api REST-Schnittstelle des WEBSALE Admin Interface API: Übersicht aller Endpunkte für Produkte, Bestellungen, Kunden, Konfiguration und mehr. Die REST API ermöglicht den Zugriff auf Funktionen und Daten eines WEBSALE Shop-Systems. Sie richtet sich an Entwickler, Integratoren und Dienstleister, die Prozesse automatisieren, Daten synchronisieren oder eigene Anwendungen anbinden möchten. ## Übersicht der zur Verfügung stehenden API-Endpunkte * [API Basics](/schnittstellen/admin-interface-api/api-basics) — Grundlagen zur Nutzung der REST API: Authentifizierung, Rechte, Abfrageparameter. * [API-Referenz Authentifizierung](/schnittstellen/admin-interface-api/api-referenz-authentifizierung) — Login über API-Schlüssel oder Benutzerkonto, Zugriffstoken, Token-Handling. * [API-Referenz Anfragen](/schnittstellen/admin-interface-api/api-referenz-anfragen) — Verwaltung und Bearbeitung eingegangener Kundenanfragen. * [API-Referenz Benutzerverwaltung](/schnittstellen/admin-interface-api/api-referenz-benutzerverwaltung) — Verwaltung von Benutzerkonten und Rechten im Admin-Interface. * [API-Referenz Bestellungen](/schnittstellen/admin-interface-api/api-referenz-bestellungen) — Abrufen, Aktualisieren und Löschen von Bestelldaten. * [API-Referenz Bildkonverter](/schnittstellen/admin-interface-api/api-referenz-bildkonverter) — Verwaltung von Produkt-, Kategoriebildern und weiteren Grafiken des Shops. * [API-Referenz Blacklist](/schnittstellen/admin-interface-api/api-referenz-blacklist) — Pflege einer Ausschlussliste für E-Mail-Adressen. * [API-Referenz CMS](/schnittstellen/admin-interface-api/api-referenz-cms) — Abruf der URL zum angebundenen Content-Management-System (Strapi). * [API-Referenz Datenfeeds](/schnittstellen/admin-interface-api/api-referenz-datenfeeds) — Erstellung und Verwaltung von Produktdatenfeeds für externe Plattformen. * [API-Referenz Gutscheine](/schnittstellen/admin-interface-api/api-referenz-gutscheine) — Verwaltung von Gutscheinen und Gutscheinvorlagen. * [API-Referenz Import](/schnittstellen/admin-interface-api/api-referenz-import) — Steuerung und Überwachung von Datenimportvorgängen. * [API-Referenz Kategorien](/schnittstellen/admin-interface-api/api-referenz-kategorien) — Erstellen, Abrufen und Zuordnen von Kategorien. * [API-Referenz Key-Value-Store](/schnittstellen/admin-interface-api/api-referenz-key-value-store) — Verwaltung von Einträgen im Redis-basierten Key-Value-Speicher. * [API-Referenz Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) — Zugriff auf globale und subshopspezifische Shop-Einstellungen. * [API-Referenz Kundendaten](/schnittstellen/admin-interface-api/api-referenz-kundendaten) — Der Endpunkt customerAccounts/ stellt eine REST-Schnittstelle zur Verfügung, über die Kundendaten im Shop-System verwaltet werden können. Die API ermöglicht das Erstellen, Abrufen, Aktualisieren und Löschen von Kundenkonten, Adressen und Bankverbindungen. Zusätzlich lassen sich Daten exportieren oder Passwortrücksetzungen initiieren. Alle Endpunkte sind so gestaltet, dass sie eine systematische Verwaltung und Pflege von Kundendaten über das Admin-Interface hinaus ermöglichen. * [API-Referenz Log Manager](/schnittstellen/admin-interface-api/api-referenz-log-manager) — Abrufen und Filtern von Systemlogs nach Zeitpunkt, Subshop oder Schweregrad. * [API-Referenz Meta-Daten](/schnittstellen/admin-interface-api/api-referenz-meta-daten) — Verwaltung von Meta-Titeln und Beschreibungen für Seiten, Produkte und Kategorien. * [API-Referenz Newsletter](/schnittstellen/admin-interface-api/api-referenz-newsletter) — Pflege von Abonnentenlisten und Zielgruppen. * [API-Referenz PayPal-Onboarding](/schnittstellen/admin-interface-api/api-referenz-paypal-onboarding) — Verwaltung von PayPal-Onboarding-Vorgängen * [API-Referenz Produkte](/schnittstellen/admin-interface-api/api-referenz-produkte) — Erstellen, Abrufen, Aktualisieren und Löschen von Produkten und Lagerbeständen. * [API-Referenz Produktbewertungen](/schnittstellen/admin-interface-api/api-referenz-produktbewertungen) — Abrufen, Bearbeiten und Löschen von Produktbewertungen. * [API-Referenz Reporter](/schnittstellen/admin-interface-api/api-referenz-reporter) — Export von Datensätzen für bestimmte Shop-Bereiche (z. B. Bestellungen, Abonnenten). * [API-Referenz SEO-URLs](/schnittstellen/admin-interface-api/api-referenz-seo-urls) — Verwaltung und Generierung suchmaschinenfreundlicher URLs. * [API-Referenz Sitemaps](/schnittstellen/admin-interface-api/api-referenz-sitemaps) — Verwaltung und Generierung von XML-Sitemaps. * [API-Referenz Statistiken](/schnittstellen/admin-interface-api/api-referenz-statistiken) — Abruf von statistischen Auswertungen zu Shop-Daten (z. B. Verkäufe, Anfragen). * [API-Referenz Stores](/schnittstellen/admin-interface-api/api-referenz-stores) — Verwaltung von Filialen (Märkten) im Shop-System. * [API-Referenz Stripe-Onboarding](/schnittstellen/admin-interface-api/api-referenz-stripe-onboarding) — Verwaltung von Stripe-Onboarding-Vorgängen * [API-Referenz Templatekompilierung](/schnittstellen/admin-interface-api/api-referenz-templatekompilierung) — Auslösen und Überwachen von Kompilierungsvorgängen für Templates. * [API-Referenz Textbausteine](/schnittstellen/admin-interface-api/api-referenz-textbausteine) — Verwaltung sprachabhängiger Texte für die Template-Ausgabe. * [API-Referenz Transaktionen](/schnittstellen/admin-interface-api/api-referenz-transaktionen) — Abrufen und Verwalten von Zahlungsinformationen. * [API-Referenz Videos](/schnittstellen/admin-interface-api/api-referenz-videos) — Verwaltung und Verlinkung von Videoinhalten im Shopsystem. # API Basics Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-basics Grundlagen der Admin Interface API: Basis-URL, Berechtigungen, Authentifizierung, Filter, Sortierung und Paginierung im WEBSALE Shop. Die REST API bietet Ihnen die Möglichkeit, automatisiert mit dem Shop-System zu interagieren – etwa um Produktdaten zu verwalten, Bestellungen auszulesen oder eigene Integrationen anzubinden. Dieses Dokument beschreibt die grundlegenden Voraussetzungen und technischen Konzepte, um mit der API arbeiten zu können. *** ## Basis-URL Alle REST-API-Endpunkte sind unter folgendem Pfad erreichbar: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.de/admin/api/v1/ ``` Diese URL ist die Basis für sämtliche Anfragen, z.B. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/admin/api/v1/products ``` ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/admin/api/v1/login ``` ## Zugang & Berechtigungen Für den Zugriff auf die REST API ist ein Benutzerkonto erforderlich, das im Admin Interface Ihres Shops verwaltet wird. Das Admin Interface ist in sogenannte Services unterteilt (z. B. Produkte, Kategorien, Sitemaps, SEO-URLs, Datenfeeds, Statistiken etc.). Für jeden Service können im Admin-Bereich Berechtigungen vergeben werden – z. B. Lesen, Bearbeiten, Erstellen, Löschen oder Publizieren. Diese Rechte gelten auch für die REST API und bestimmen, auf welche Endpunkte Sie zugreifen und welche HTTP-Methoden (GET, POST, PUT, DELETE) Sie verwenden dürfen. Ein Benutzer mit z. B. nur Leserechten im Service „Produkte“ kann Produkte per API nur abrufen (GET), aber nicht bearbeiten (PUT/POST/DELETE). Ihre zugewiesenen Rechte können Sie im Admin Interface unter folgendem Pfad einsehen: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.de/admin/profile ``` Die Vergabe von Rechten erfolgt über den Service „Benutzer“: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.de/admin/administration/users ``` Einige Endpunkte arbeiten mit subshopspezifischen Daten. In diesen Fällen muss der betreffende Subshop explizit angegeben werden. Das betrifft unter anderem Methoden für Produkte, Kategorien, Lagerbestände, SEO-Daten und ähnliche kontextabhängige Inhalte. Der Subshop kann auf zwei gleichwertigen Wegen übergeben werden - als URL-Parameter oder als HTTP-Header: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.de/admin/api/v1/categories?subshopId=deutsch ``` ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} X-SubshopId: deutsch ``` Die Auswertung erfolgt in dieser Reihenfolge: 1. URL-Parameter `subshopId` - hat Vorrang, sobald er gesetzt ist. 2. Header `X-SubshopId` - greift, wenn der URL-Parameter fehlt oder leer ist. 3. Fallback: der erste im Shop konfigurierte Subshop. Der Header ist praktisch, wenn Ihr Integrationsclient durchgängig mit demselben Subshop arbeitet: Dann setzen Sie ihn einmal global, statt ihn an jede URL zu hängen. Verlassen Sie sich nicht auf den Fallback aus Punkt 3, da Sie sonst im ersten konfigurierten Subshop arbeiten. Das ist selten der gewünschte Subshop und er kann sich ändern, wenn die Subshop-Konfiguration angepasst wird. Geben Sie deshalb den Subshop bei subshopbezogenen Endpunkten immer explizit an. Endpunkte ohne Subshop-Bezug (z. B. Login oder Benutzerverwaltung) werten weder den Parameter noch den Header aus. Falls Ihnen der Zugriff auf bestimmte REST-Endpunkte verweigert wird, fehlen Ihnen möglicherweise die erforderlichen Rechte. In diesem Fall wenden Sie sich an den zuständigen Shop-Administrator. *** ## Authentifizierung Für den Zugriff auf geschützte REST-API-Endpunkte ist eine Anmeldung erforderlich. Die Authentifizierung erfolgt entweder über Benutzername/Passwort oder per API-Schlüssel. Erfolgreich authentifizierte Anfragen erhalten ein Access Token, mit dem weitere Endpunkte angesprochen werden können. Zusätzlich wird ein Refresh Token bereitgestellt. Der Login erfolgt über folgenden Endpunkt: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/admin/api/v1/login ``` Das erhaltene Access Token muss bei allen folgenden API-Aufrufen im HTTP-Header mitgesendet werden. Der Header muss dazu das Feld `X-Authorization` enthalten. Der Wert besteht aus dem Wort `Bearer`, gefolgt vom Token: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "X-Authorization": "Bearer " ``` Details zur Authentifizierung (Request-Varianten, Token-Verwendung, Fehlercodes etc.) finden Sie in der separaten Dokumentation: [API-Referenz Authentifizierung](/schnittstellen/admin-interface-api/api-referenz-authentifizierung) *** ## Filter, Sortierung & Paginierung Viele REST-Endpunkte liefern Listen von Daten – etwa Produkte, Bestellungen oder Kategorien. Um mit diesen Daten effizient zu arbeiten, stellt die API verschiedene Parameter zur Verfügung, mit denen sich die Ergebnisse eingrenzen, sortieren und seitenweise abrufen lassen. Diese Mechanismen sind besonders bei großen Datenmengen wichtig, um performante und gezielte Abfragen zu ermöglichen. Ein API-Aufruf kann dabei verschiedene Parameter enthalten. Ein typischer GET-Request könnte wie folgt aussehen: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.de/admin/api/v1/?size=100&sort=field1:asc&filter_eq[field2]=value&pageToken=MTAw ``` Die Antwort der API ist standardisiert aufgebaut und enthält neben den angeforderten Datensätzen weitere Meta-Informationen wie den `nextPageToken`, den Gesamtzähler (`totalCount`) sowie das Flag `endReached`, das angibt, ob weitere Seiten zur Verfügung stehen: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [...], "nextPageToken": "MTAx", "totalCount": 123 } ``` ### Unterstützte Parameter Die folgenden URL-Parameter werden zur Steuerung von Ergebnislisten unterstützt. Die Schreibweise ist case-sensitive. | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `size` | Anzahl der zurückgegebenen Einträge pro Seite (1 bis **maximal 300**) | | `pageToken` | Optionaler Paginierungsmarker für den Abruf der nächsten Seite | | `sort` | Ergebnis-Sortierung nach einem oder mehreren Feldern | | `filter_...` | Filterbedingungen zur Einschränkung der Ergebnisse | | `subshopId` | Einschränkung auf einen bestimmten Subshop. Bei subshopbezogenen Endpunkten (z. B. Produkte, Kategorien, Lagerbestände, SEO) erforderlich. Alternativ als Header `X-SubshopId` übergebbar – siehe [Zugang & Berechtigungen](#zugang--berechtigungen). | | `textSearch` | Optionaler Parameter für die Volltextsuche. | ### Anzahl & Paginierung Die Anzahl der zurückgegebenen Datensätze pro API-Anfrage kann über den Parameter `size` gesteuert werden. Der Wert muss eine Ganzzahl zwischen 1 und 300 sein. Wird kein `size`-Parameter übergeben, verwendet die API standardmäßig einen Wert von 100 Einträgen pro Seite. Ist die angeforderte Datenmenge größer als der definierte `size`-Wert (bzw. größer als der Standardwert), liefert die API in der Antwort einen `nextPageToken`, mit dem weitere Seiten geladen werden können. Der Paginierungsmechanismus erlaubt es, große Datenmengen schrittweise abzurufen. #### Beispiel Beispiel für eine manuell gesetzte Seitengröße. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.de/admin/api/v1/?size=50 ``` #### Fehlercodes | **Fehlercode** | **Typ** | **Beschreibung** | | -------------- | ------------------ | -------------------------------------- | | 400 | `InvalidCharacter` | Ungültige Zeichen im Parameterwert | | 400 | `InvalidValue` | Wert kleiner als 1 oder größer als 300 | Der Parameter `pageToken` ermöglicht den Zugriff auf die Folgeseiten von Ergebnislisten. Der Wert wird von der API automatisch als `nextPageToken` zurückgegeben und muss base64-url-kodiert übergeben werden. Bei einer fehlerhaften oder ungültigen Codierung erfolgt eine Fehlermeldung. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.de/admin/api/v1/?size=100&pageToken=MTAw ``` #### Fehlercodes | **Fehlercode** | **Typ** | **Beschreibung** | | -------------- | ------- | -------------------------------------------------- | | 400 | | Token nicht dekodierbar oder negativ bzw. ungültig | ### Sonderfall: Produkte Das Laden von Produkten mittels pageToken kann langsam sein, wenn mehr als 10.000 Produkte im Shop existieren. Neben dem pageToken wird bei Produkten auch ein `searchAfterToken` zurückgegeben. Statt `pageToken` kann `searchAfterToken` in der URL angegeben werden, um auch bei vielen Ergebnissen die Produkte effizient laden zu können. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.de/admin/api/v1/?size=300&searchAfterToken=WzAuMCwiMTAwLTQxMjMyLTk3NDFfZGV1dHNjaF8zIl0 ``` ### Sortierung Die Sortierung von Ergebnissen erfolgt über den Parameter `sort`. Er erwartet als Wert einen Feldnamen und eine Sortierrichtung (`asc` für aufsteigend, `desc` für absteigend), getrennt durch einen Doppelpunkt. Für die Kombination mehrerer Sortierkriterien ist es erforderlich, mehrere sort-Parameter zu übergeben. Jeder Parameter steht dabei für ein einzelnes Kriterium. Eine kommaseparierte Liste innerhalb eines Parameters wird nicht unterstützt. Falls kein Sortierparameter angegeben ist, wird standardmäßig nach der internen ID sortiert. Eine Ausnahme ist die Produktliste mit dem Filter `inCategory`: Dort gilt ohne eigenen `sort`-Parameter die im Shop gepflegte Kategoriereihenfolge – siehe [Produkte – Reihenfolge bei `inCategory`](/schnittstellen/admin-interface-api/api-referenz-produkte#reihenfolge-bei-incategory). #### Syntax ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} sort=:asc|desc ``` #### Sortierung nach Preis aufsteigend ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.de/admin/api/v1/?sort=price:asc ``` Ein weiteres Beispiel für eine Sortierung nach dem Namen (aufsteigend) und anschließend nach dem Preis (absteigend): ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.de/admin/api/v1/?sort=name:asc&sort=price:desc ``` #### Fehlercodes | **Fehlercode** | **Typ** | **Beschreibung** | | -------------- | -------------- | --------------------------------------------------- | | 400 | `SyntaxError` | Fehlender oder mehrfach vorhandener Doppelpunkt. | | 400 | `InvalidValue` | Ungültige Sortierrichtung (nicht `asc` oder `desc`) | | 400 | `UnknownField` | Das angegebene Sortierfeld ist unbekannt | ### Filter Filter ermöglichen eine gezielte Einschränkung von Ergebnislisten. Jeder Filter folgt dem Muster. #### Syntax ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} filter_[]= ``` Mehrere Filter für unterschiedliche Felder werden logisch mit **UND** verknüpft. Wenn mehrere Filter für dasselbe Feld angegeben werden, interpretiert die API diese als **ODER**-Verknüpfung. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ?filter_eq[status]=open &filter_gte[createdAt]=2024-12-01T00:00:00Z &filter_lte[createdAt]=2025-01-05T23:59:59Z ``` #### Unterstützte Filteroperationen | **Operation** | **Bedeutung** | | ------------- | -------------------------------------------------------------------- | | `eq` | Gleichheit (`=`) | | `neq` | Ungleichheit (`!=`) | | `lt` | Kleiner als (`<`) | | `lte` | Kleiner oder gleich (`≤`) | | `gt` | Größer als (`>`) | | `gte` | Größer oder gleich (`≥`) | | `beginsWith` | Beginnt mit | | `endsWith` | Endet mit | | `contains` | Enthält | | `notContains` | Enthält nicht | | `within` | Liste enthält den angegebenen Wert (nur Felder vom Typ Liste) | | `notWithin` | Liste enthält den angegebenen Wert nicht (nur Felder vom Typ Liste) | | `empty` | Feld ist leer bzw. nicht gesetzt (nur Felder vom Typ Liste oder Map) | Die Operationen `within`, `notWithin` und `empty` stehen nur bei der Produktliste zur Verfügung (`GET products` und die davon abgeleiteten Endpunkte), weil nur dort Felder vom Typ Liste und Map vorkommen. Bei allen anderen Listen-Endpunkten führen sie zum Fehler `UnknownOperation`. #### Erlaubte Operationen je Feldtyp Nicht auf jedem Feld ist eine Filteroperation erlaubt. Welche Operationen gültig sind, hängt vom Datentyp des Feldes ab. Die Aussage "Alle Produktdatenfelder sind filterbar" bedeutet also nicht, dass jedes Feld mit jeder Operation kombinierbar ist. Eine unzulässige Kombination wird nicht ignoriert, sondern mit dem Statuscode `400 Bad Request` und dem Typ `illegalOperation` abgewiesen. | **Feldtyp** | **Erlaubte Operationen** | | ---------------------------------------- | ---------------------------------------------------------------- | | Text (String) | `eq`, `neq`, `contains`, `notContains`, `beginsWith`, `endsWith` | | Aufzählung (Enum), z. B. `active` | `eq`, `neq` | | Wahrheitswert (Bool) | `eq`, `neq` | | Zahl (Integer, Float), Preis, Datum/Zeit | `eq`, `neq`, `lt`, `lte`, `gt`, `gte` | | Liste | `within`, `notWithin`, `empty` | | Map | `empty` | | Bild, Video | keine – diese Felder sind nicht filterbar | Beispiele: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} # gültig: Text-Feld mit contains ?filter_contains[name]=Polo # gültig: Enum-Feld mit eq ?filter_eq[active]=always # ungültig -> 400 "illegalOperation": Enum-Feld mit contains ?filter_contains[active]=alw ``` Benutzerdefinierte Felder werden mit dem Präfix `custom.` adressiert: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ?filter_eq[custom.brand]=Barbour ``` Es gibt **keine** Operationen `like` oder `in`. Verwenden Sie stattdessen `contains` (Teilstring-Suche) bzw. mehrere Filter auf dasselbe Feld, die die API als ODER verknüpft: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ?filter_eq[taxRateId]=1&filter_eq[taxRateId]=7 ``` #### Fehlercodes | **Fehlercode** | **Typ** | **Beschreibung** | | -------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------- | | 400 | `UnknownOperation` | Die Filteroperation ist nicht bekannt | | 400 | `UnknownField` | Das angegebene Feld ist ungültig | | 400 | `illegalOperation` | Die Operation ist für den Datentyp dieses Feldes nicht erlaubt (siehe Tabelle „Erlaubte Operationen je Feldtyp") | | 400 | `invalidCharacters` | Der Filterwert enthält ungültige Zeichen | ### Volltextsuche Die meisten Endpunkte unterstützen eine Volltextsuche über den optionalen URL-Parameter `textSearch`. Damit lassen sich Ergebnisse nach einem Suchbegriff filtern, ohne explizite Filterfelder angeben zu müssen. Der Parameter kann mehrfach angegeben werden – mehrere Werte werden mit OR verknüpft. Die Suche ist schreibungsabhängig. #### Syntax ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} textSearch=&textSearch= ``` #### Beispiel (einzelner Suchbegriff) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.de/admin/api/v1/orders?textSearch=Mustermann ``` #### Beispiel (mehrere Suchbegriffe) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.de/admin/api/v1/orders?textSearch=Mustermann&textSearch=Berlin ``` *** ## Bulk-Endpunkte Für Massenoperationen stellt die API Bulk-Endpunkte bereit. Sie übertragen viele Datensätze in einem Request und sind deutlich effizienter als Einzelaufrufe. ### Gemeinsames Limit: 1000 Einträge pro Request **Alle** Bulk-Endpunkte teilen sich ein Limit von 1.000 Einträgen pro Anfrage. Es handelt sich dabei nicht um ein Limit einzelner Endpunkte, sondern um eine gemeinsame Obergrenze, die an jedem der unten aufgeführten Endpunkte identisch ist. Wird das Limit überschritten, antwortet die API mit `400 Bad Request`. In diesem Fall werden keine Einträge verarbeitet und der Request wird komplett abgewiesen. Zerlegen Sie daher größere Datenmengen client-seitig in Blöcke von maximal 1.000 Einträgen. | **Endpunkt** | **Methode** | **Referenz** | | --------------------------------- | ------------ | --------------------------------------------------------------------------- | | `bulk/products` | POST | [Produkte](/schnittstellen/admin-interface-api/api-referenz-produkte) | | `bulk/products/variants` | POST | [Produkte](/schnittstellen/admin-interface-api/api-referenz-produkte) | | `bulk/products/inventory` | POST | [Produkte](/schnittstellen/admin-interface-api/api-referenz-produkte) | | `bulk/customerAccounts` | POST | [Kundendaten](/schnittstellen/admin-interface-api/api-referenz-kundendaten) | | `bulk/customerAccounts/addresses` | POST | [Kundendaten](/schnittstellen/admin-interface-api/api-referenz-kundendaten) | | `vouchers/bulk` | POST, DELETE | [Gutscheine](/schnittstellen/admin-interface-api/api-referenz-gutscheine) | Alle schreibenden Bulk-Endpunkte arbeiten mit **POST**, auch wenn sie bestehende Datensätze aktualisieren. Ein `PUT` auf einen Bulk-Pfad wird nicht beantwortet. *** ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Anfragen Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-anfragen Kundenanfragen über den Endpunkt inquiries/ der Admin Interface API abrufen, deren Bearbeitungsstatus ändern und einzelne Anfragen löschen. Der Endpunkt `inquiries/` ermöglicht es, Anfrage-Daten abzufragen sowie zu löschen und ihren Status zu aktualisieren. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | --------------- | ------------- | --------------------- | ------------------- | --------------------- | --------------------- | | **Anfragen** | inquiries/ | | | | | ## Datenfelder | **Name** | **Typ** | **Bedeutung** | | ---------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **id** | String | Eindeutige ID der Anfrage | | **subshopId** | String | Angabe des Subshops, in dem die Anfrage eingegangen ist (z. B. „deutsch“) | | **processingStatus** | INT | Bearbeitungsstatus der Anfrage:
    `0` = New (neu eingegangen)
    `1` = Read (gelesen)
    `2` = Answered (beantwortet)
    `3` = Closed (abgeschlossen) | | **data** | Objekt | Enthält Formularfelder und zusätzliche Meta-Daten der Anfrage als JSON-Objekt | | **data**.**fields** | Array | Enthält den technischen Namen des Feldes, sein Label (Bezeichnung) und den übergebenen Wert | | **data**.**inquiryConfigId** | String | ID der Konfiguration, über die das Anfrageformular erstellt wurde | | **data**.**inquiryId** | String | Eindeutige ID der Anfrage | | **data**.**shopId** | String | Technischer Name des Shops | | **data**.**submitter** | Objekt | Enthält die E-Mail-Adresse, die IP-Adresse und die ID der Session des Einsenders | | **data**.**subshopId** | String | Angabe des Subshops, in dem die Anfrage eingegangen ist (z. B. „deutsch“) | | **createdAt** | String | Datum und Uhrzeit der Erstellung der Anfrage (im ISO 8601-Format, UTC) | | **updatedAt** | String | Datum und Uhrzeit der letzten Änderung der Anfrage (im ISO 8601-Format, UTC) | ### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2024-10-11T12:03:48Z", "data": { "fields": [ { "label": "Vorname", "name": "firstName", "value": "Foo" }, { "label": "Nachname", "name": "lastName", "value": "Bar" }, { "label": "Betreff", "name": "subject", "value": "mySubject" }, { "label": "Kundennummer", "name": "customerNumber", "value": "11" }, { "label": "Text", "name": "text", "value": "myMessage" } ], "inquiryConfigId": "contact", "inquiryId": "4dea07ff679aa8b4", "shopId": "myshop", "submitter": { "emailAddress": "email@email.com", "ipAddress": "172.18.0.XXX", "sessionId": "cf41e72fadae3eaeb0aeca63d..." }, "subshopId": "deutsch" }, "id": "4dea07ff679aa8b4", "processingStatus": 0, "subshopId": "deutsch", "updatedAt": "2024-10-11T12:03:48Z" } ``` ## Verwendung der Methoden ### GET inquiries Ruft eine Liste aller vorhandenen Anfragen ab – mit Filter- und Sortiermöglichkeiten. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/inquiries ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "createdAt": "2024-10-11T12:03:48Z", "data": { "fields": [ { "label": "Vorname", "name": "firstName", "value": "Foo" }, ... ], "inquiryConfigId": "contact", "inquiryId": "4dea07ff679aa8b4", "shopId": "myshop", "submitter": { "emailAddress": "email@email.com", "ipAddress": "172.18.0.XXX", "sessionId": "cf41e72fadae3eaeb0aeca63d..." }, "subshopId": "deutsch" }, "id": "4dea07ff679aa8b4", "processingStatus": 0, "subshopId": "deutsch", "updatedAt": "2024-10-11T12:03:48Z" }, ... ], "nextPageToken": "NQ", "totalCount": 6 } ``` #### Filterfelder `createdAt`, `updatedAt`, `id`, `subshopId`, `processingStatus`, `inquiryConfigId` #### Sortierfelder `createdAt`, `updatedAt`, `id`, `subshopId`, `processingStatus` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------- | ------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Anfragen. | | 400 Bad Request | "invalidValue" | `size` ∉ \[1;300]
    `pageToken` ist keine Zahl oder kleiner als 0. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | | 503 Service Unavailable | "internalError" | Nicht alle Anfragen konnten entschlüsselt werden. | ### GET inquiries/\{inquiryId} Ruft die Details einer einzelnen Anfrage anhand ihrer ID ab. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/inquiries/4dea07ff679aa8b4 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2024-10-11T12:03:48Z", "data": { "fields": [ { "label": "Vorname", "name": "firstName", "value": "Foo" }, { "label": "Nachname", "name": "lastName", "value": "Bar" }, { "label": "Betreff", "name": "subject", "value": "mySubject" }, { "label": "Kundennummer", "name": "customerNumber", "value": "11" }, { "label": "Text", "name": "text", "value": "myMessage" } ], "inquiryConfigId": "contact", "inquiryId": "4dea07ff679aa8b4", "shopId": "myshop", "submitter": { "emailAddress": "email@email.com", "ipAddress": "172.18.0.XXX", "sessionId": "cf41e72fadae3eaeb0aeca63d..." }, "subshopId": "deutsch" }, "id": "4dea07ff679aa8b4", "processingStatus": 0, "subshopId": "deutsch", "updatedAt": "2024-10-11T12:03:48Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Anfragen. | | 404 Not Found | | Die Anfrage wurde nicht gefunden. | | 503 Service Unavailable | "internalError" | Die Anfrage konnte nicht entschlüsselt werden. | ### GET inquiries/open Dieser Endpunkt liefert eine Übersicht über die Anzahl offener Anfragen, gruppiert nach Anfragekonfigurationen. Die Antwort enthält eine Liste von Objekten, wobei jedes Objekt die Anzahl offener Anfragen (`count`) sowie die zugehörige Anfragekonfiguration (`inquiryConfigId`) angibt. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/inquiries/open ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 3, "inquiryConfigId": "catalogue" }, { "count": 15, "inquiryConfigId": "contact" }, { "count": 1, "inquiryConfigId": "productQuestion" }, { "count": 1, "inquiryConfigId": "returnInquiry" } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Anfragen. | | 503 Service Unavailable | "internalError" | Anfragen konnten nicht geladen werden. | ### PUT inquiries/\{inquiryId} Aktualisiert den Bearbeitungsstatus einer bestimmten Anfrage. Mögliche Werte für `processingStatus`: * `0` = New * `1` = Read * `2` = Answered * `3` = Closed #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/inquiries/bda4c9c28ebc6920 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "processingStatus": 1 } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2024-10-11T12:03:48Z", "data": { "fields": [ { "label": "Vorname", "name": "firstName", "value": "Foo" } ], "inquiryConfigId": "contact", "inquiryId": "bda4c9c28ebc6920", "shopId": "myshop", "submitter": { "emailAddress": "email@email.com", "ipAddress": "172.18.0.XXX", "sessionId": "cf41e72fadae3eaeb0aeca63d..." }, "subshopId": "deutsch" }, "id": "bda4c9c28ebc6920", "processingStatus": 1, "subshopId": "deutsch", "updatedAt": "2024-10-11T12:05:00Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | ----------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Anfragen. | | 400 Bad Request | | Request-Body konnte nicht als JSON geladen werden.
    Das Aktualisieren ist fehlgeschlagen. | | 400 Bad Request | "missing" | `processingStatus` wurde nicht übergeben. | | 400 Bad Request | "unknownDataField" | Es wird versucht, ein unbekanntes Feld zu übergeben. Nur `processingStatus` ist erlaubt. | | 400 Bad Request | "invalidFormat" | `processingStatus` ist keine Zahl. | | 400 Bad Request | "invalidValue" | `processingStatus` ist außerhalb des gültigen Bereichs (0–3). | | 404 Not Found | | Die Anfrage wurde nicht gefunden. | | 503 Service Unavailable | "internalError" | Die Anfrage konnte nicht entschlüsselt werden. | ### DELETE inquiries/\{inquiryId} Löscht eine bestimmte Anfrage dauerhaft. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/inquiries/bda4c9c28ebc6920 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | --------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Anfragen. | | 404 Not Found | | Die Anfrage wurde nicht gefunden. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Authentifizierung Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-authentifizierung Anmeldung an der Admin Interface API per Benutzerkonto oder API-Schlüssel, Access- und Refresh-Token verwalten sowie Passwörter zurücksetzen. Die API-Referenz Authentifizierung beschreibt, wie sich Benutzer über die REST API anmelden können. Die Anmeldung erfolgt mit einem Benutzerkonto, das im Admin Interface des Shops verwaltet wird.\ Nach erfolgreicher Authentifizierung können – je nach zugewiesenen Rechten – weitere REST-API-Endpunkte genutzt werden, z. B. zum Bearbeiten von Anfragen oder Verwalten von Bestellungen. ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | --------------------- | ------------- | --------------------------- | --------------------------- | ------------------------- | ------------------------- | | **Authentifizierung** | login/ |
    |
    |
    |
    | ## Allgemein Um auf die REST API zugreifen zu können, benötigen Sie ein Benutzerkonto für das Admin-Interface des Shops. Die Rechte und Rollen dieses Kontos steuern, auf welche REST-API-Endpunkte Sie zugreifen dürfen und welche HTTP-Methoden (`GET`, `POST`, `PUT`, `DELETE`) Ihnen zur Verfügung stehen. Beispiel: * Ein Benutzer mit nur Leserechten kann Anfragen abrufen, aber nicht bearbeiten oder löschen. * Ein Benutzer mit Administratorrechten hat vollen Zugriff auf alle REST-Dienste und Methoden. Wenn der Zugriff auf bestimmte REST-Endpunkte verweigert wird, fehlt Ihrem Benutzerkonto vermutlich die entsprechende Berechtigung. Wenden Sie sich in diesem Fall an den zuständigen Shop-Administrator. Weitere Informationen zur Verwaltung von Benutzern und zur Vergabe von Rechten finden Sie im Abschnitt [API-Referenz Benutzerverwaltung](/schnittstellen/admin-interface-api/api-referenz-benutzerverwaltung). ## Verwendung der Methoden ### GET login/checkToken/\{otok} Dieser Endpunkt überprüft ein Double-Opt-in-Token **(**`otok`**)** auf Gültigkeit. Er wird z. B. im Rahmen des Passwort-Zurücksetzen-Prozesses verwendet. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/login/checkToken/ ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true, "id": } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | --------------- | -------------- | ---------------------------------------------------------------------------------------- | | 400 Bad Request | "missing" | `otok` fehlt. | | 400 Bad Request | "invalidValue" | `otok` ist ungültig oder schon genutzt oder ermöglicht es nicht, das Passwort zu ändern. | | 404 Not Found | | Das Konto wurde nicht gefunden. | ### POST login Dieser Endpunkt ermöglicht die Anmeldung über E-Mail/Passwort oder einen API-Schlüssel (`apiKey`). Bei erfolgreicher Authentifizierung werden ein `accessToken` und ein `refreshToken` zurückgegeben. Wird der Parameter `?setCookie` in der URL angegeben, werden die Tokens als Cookies gesetzt und das `refreshToken` wird nicht in der JSON-Antwort zurückgegeben. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/login ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "grantType": "apiKey", "apiKey": } ``` oder ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "grantType": "password", "user": , "password": } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true, "accessToken": , "refreshToken": } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------- | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 401 Unauthorized | | Das Konto hat `id` 0. | | 403 Forbidden | | Das Konto ist gesperrt. | | 404 Not Found | | Das Konto konnte nicht geladen werden. | | 503 Service Unavailable | "internalError" | Refresh-Token konnte nicht erstellt werden. | ### POST login/refresh Dieser Endpunkt stellt ein neues `accessToken` aus, das über ein gültiges `refreshToken` autorisiert wird. Wird der Parameter `?setCookie` in der URL angegeben, setzt der Endpunkt das neue `accessToken` zusätzlich als Cookie. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/login/refresh ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "refreshToken": } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true, "accessToken": } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ---------------------------------------------------------------------------------- | | 400 Bad Request | | Request body konnte nicht geladen werden.
    Der Tokentyp ist nicht "Refresh". | | 400 Bad Request | "invalidFormat" | `refreshToken` hat einen ungültigen Typ (erwartet: String). | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde gesendet. | | 401 Unauthorized | | Der Token ist abgelaufen. | | 403 Forbidden | | Das Konto ist gesperrt. | | 404 Not Found | | Der Token oder das korrespondierende Konto wurden nicht gefunden. | ### POST login/passwordLink Dieser Endpunkt versendet eine E-Mail mit einem Link zum Zurücksetzen des Passworts an die angegebene E-Mail-Adresse. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/login/passwordLink ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "m.mustermann@websale.de" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | ----------------------------------------- | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "missing" | `email` fehlt. | | 400 Bad Request | "invalidValue" | `email` ist ein leerer String. | | 400 Bad Request | "invalidFormat" | `email` ist kein String. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde gesendet. | | 404 Not Found | | Das Konto wurde nicht gefunden. | | 503 Service Unavailable | "internalError" | E-Mail konnte nicht gesendet werden. | ### POST login/setPassword Dieser Endpunkt setzt ein neues Passwort für ein Benutzerkonto. Die Aktion muss durch ein gültiges Double-Opt-in-Token autorisiert sein, das zuvor per E-Mail (`login/paswordLink`) versendet wurde. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/login/setPassword ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "password_new": , "password_new_again": , "otok": } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | --------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 400 Bad Request | | Request body konnte nicht geladen werden.
    Das `Double-Opt-in-Token` ist ungültig oder ermöglicht es nicht, das Passwort zu ändern.
    Das Passwort ist zu schwach. | | 400 Bad Request | "missing" | `Double-Opt-in-Token`, `password_new` oder `password_new_again` fehlen. | | 400 Bad Request | "invalidValue" | `password_new` und `password_new_again` stimmen nicht überein.
    Das Passwort ist kürzer als 12 Zeichen.
    `password_new`, `password_new_again` oder `otok` sind leere Strings. | | 400 Bad Request | "invalidFormat" | `password_new`, `password_new_again` oder `otok` sind keine Strings. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde gesendet. | | 403 Forbidden | | Das Konto ist gesperrt. | | 404 Not Found | | Das Konto wurde nicht gefunden. | ### POST login/logout Dieser Endpunkt meldet den aktuellen Benutzer ab. Dabei werden die gesetzten Cookies für `accessToken` und `refreshToken` gelöscht und der Refresh-Token aus der Datenbank entfernt. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/login/logout ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | --------------- | ------- | ----------------------------------------- | | 400 Bad Request | | Request body konnte nicht geladen werden. | # API-Referenz Benutzerverwaltung Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-benutzerverwaltung Benutzerkonten, Rollen und Berechtigungen für das WEBSALE Admin Interface per REST API anlegen, bearbeiten, löschen und individuell konfigurieren. Die API-Referenz Benutzerverwaltung beschreibt Endpunkte zur Verwaltung von Benutzerkonten und individuellen Einstellungen im Admin Interface des Shops. Über die Schnittstelle lassen sich Benutzer anlegen, bearbeiten und löschen sowie persönliche Einstellungen wie Sprache oder Dashboard-Konfiguration abrufen und aktualisieren. Der Zugriff auf die jeweiligen Endpunkte richtet sich nach den Berechtigungen des angemeldeten Benutzers. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | --------------------------------------------------------------------------------------------------------- | -------------- | --------------------- | --------------------- | --------------------- | --------------------- | | [**Benutzerkonto im Admin-Bereich**](/schnittstellen/admin-interface-api/api-referenz-benutzerverwaltung) | admin/user | | | | | | [**Benutzereinstellungen**](/schnittstellen/admin-interface-api/api-referenz-benutzerverwaltung) | admin/settings | | | | | ## Allgemein ### Datenfelder eines Benutzerkontos | **Name** | **Typ** | **Verwendung** | | --------------- | ------- | --------------------------------------------------------------------------------------------------------------- | | **id** | Integer | Eindeutige ID des Benutzers | | **firstName** | String | Vorname des Benutzers | | **lastName** | String | Nachname des Benutzers | | **role** | Array | Rollen im Unternehmen als Array, z.B. \["marketing", "seo"] | | **email** | String | E-Mail-Adresse des Benutzers | | **userName** | String | Benutzername des Benutzers | | **permissions** | Objekt | [Berechtigungen](/schnittstellen/admin-interface-api/api-referenz-benutzerverwaltung) des Benutzers für Dienste | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "vx-shop@websale.de", "firstName": "Horst", "id": 1, "lastName": "Schlämmer", "userName": "vx-shop", "permissions": { "admin": { "0": true } }, "role": ["productMaintainer"] } ``` ### Datenfelder der Benutzereinstellungen | **Name** | **Typ** | **Verwendung** | | ---------------------------------------------------- | ------- | ----------------------------------------------------------- | | **dashboard.content\[]** | Array | Liste von konfigurierten Widgets auf dem Benutzer-Dashboard | | **dashboard.content\[].position.cols** | Integer | Anzahl der Spalten, die das Widget belegt | | **dashboard.content\[].position.rows** | Integer | Anzahl der Zeilen, die das Widget belegt | | **dashboard.content\[].position.x** | Integer | Horizontale Position des Widgets im Raster | | **dashboard.content\[].position.y** | Integer | Vertikale Position des Widgets im Raster | | **dashboard.content\[].settings** | Object | Individuelle Einstellungen für das jeweilige Widget | | **dashboard.content\[].settings.shortcuts\[]** | Array | (Nur für Widget „shortcuts“) Liste mit Link-Shortcuts | | **dashboard.content\[].settings.shortcuts\[].label** | String | Text, der auf dem Button angezeigt wird | | **dashboard.content\[].settings.shortcuts\[].route** | String | Interne Route, die beim Klick geöffnet wird | | **dashboard.content\[].widgetId** | String | Eindeutige Kennung des verwendeten Widgets | | **firstName** | String | Vorname des Benutzers | | **language** | String | Sprachcode des Benutzers (z. B. „deu“) | | **lastName** | String | Nachname des Benutzers | | **salutation** | String | Anrede des Benutzers (`m`, `w` oder `d`) | | **colorScheme** | String | Farbschema des Admin-Interfaces | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "dashboard": { "content": [ { "position": { "cols": 3, "rows": 4, "x": 0, "y": 0 }, "settings": {}, "widgetId": "salesTrend" }, { "position": { "cols": 3, "rows": 2, "x": 0, "y": 4 }, "settings": {}, "widgetId": "inbox" }, { "position": { "cols": 2, "rows": 3, "x": 3, "y": 0 }, "settings": {}, "widgetId": "conversion-rate-trends" }, { "position": { "cols": 2, "rows": 5, "x": 3, "y": 3 }, "settings": { "shortcuts": [ { "label": "Zu Kategorien", "route": "/categories" }, { "label": "Zu Produkten", "route": "/products" }, { "label": "Zu Bestellungen", "route": "/orders" } ] }, "widgetId": "shortcuts" } ] }, "firstName": "Horst", "language": "deu", "lastName": "Schlämmer", "salutation": "m", "colorScheme": "light" } ``` ### Berechtigungen | **Technischer Name** | **Bedeutung** | **Werte** | | -------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------- | | `"admin"` | Vollzugriff auf alle Bereiche | `0 = Active` | | `"products"` | Produkte | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete`
    `4 = WriteProtectedFields` | | `"productvariants"` | Produktvarianten | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete` | | `"productRatings"` | Produktbewertungen | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete` | | `"inventory"` | Produkte Lagerbestand | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete` | | `"productFields"` | Produktfelder | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete` | | `"categories"` | Kategorien | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete` | | `"categoryFields"` | Kategoriefelder | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete` | | `"configuration"` | Konfigurationen | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete` | | `"seo"` | SEO | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete` | | `"sitemaps"` | SiteMaps | `0 = Read`
    `1 = Create`
    `2 = Write`
    `3 = Delete`
    `4 = Publish` | | `"datafeeds"` | Datenfeeds | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete`
    `4 = Publish` | | `"orders"` | Bestellungen | `0 = Read`
    `1 = Write`
    `2 = Delete` | | `"inquiries"` | Anfragen | `0 = Read`
    `1 = Write`
    `2 = Delete` | | `"texts"` | Textbausteine | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete`
    `4 = Publish` | | `"templates"` | Shop-Seiten-Templates | `0 = Read`
    `4 = Publish` | | `"customerAccounts"` | Kundendaten | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete` | | `"vouchers"` | Gutscheine | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete` | | `"transactions"` | Transaktionen | `0 = Read`
    `1 = Write` | | `"keyValue"` | Key-Value-Store | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete` | | `"newsletter"` | Newsletter | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete` | | `"blacklist"` | Newsletter-Blacklist | `0 = Add`
    `1 = Remove` | | `"statistics"` | Alle Statistiken | `0 = Read` | | `"logs"` | Logs | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete` | | `"strapi"` | Link zum Strapi-CMS | `0 = Read` | | `"dashboard"` | Dashboard im AI | `0 = Read` | | `"imageconverter"` | Bildkonverter | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete`
    `4 = Publish` | | `"paypalonboarding"` | Paypal-Onboarding | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete` | | `"paymentprovider"` | Payment provider | `0 = Read`
    `1 = Write`
    `2 = Create`
    `3 = Delete` | #### Beispiel der Berechtigungen ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "permissions": { "admin": { "0": false }, "newsletter": { "0": true, "1": true, "2": true, "3": true }, "customerAccounts": { "0": true, "1": false, "2": false, "3": false }, "products": { "0": true, "1": false, "2": false, "3": false, "4": false } } ``` Der Benutzer hat keinen Vollzugriff (die Berechtigung `admin.0` (`admin.active`) ist auf `false` gesetzt). Er kann den gesamten Newsletter-Dienst nutzen – die Berechtigungen `newsletter.0` (`newsletter.Read`), `newsletter.1` (`newsletter.Write`), `newsletter.2` (`newsletter.Create`) und `newsletter.3` (`newsletter.Delete`) sind auf `true` gesetzt, und Kunden- sowie Produkt-Daten lesen – `customerAccounts.0` (`customerAccounts.Read`) und `products.0` (`products.Read`) sind auf `true` gesetzt. ## Methoden für Benutzerkonten Der Endpunkt `/admin/user` ermöglicht die Verwaltung von Benutzerkonten. Darüber können Benutzer erstellt, geändert, gelöscht und abgerufen werden. ### GET admin/user Dieser Endpunkt liefert eine Liste aller Benutzerkonten aus dem Admin Interface des Shops. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/admin/user ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "id": 1, "role": [], "firstName": "", "lastName": "", "email": "", "permissions": {...} }, ... ], "nextPageToken": "NA", "totalCount": 5 } ``` #### Filterfelder `id`, `firstName`, `lastName`, `email`, `privileges`, `websale` #### Sortierfelder `id`, `firstName`, `lastName`, `email`, `websale` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | -------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Benutzern. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET admin/user/self Dieser Endpunkt lädt die Daten des aktuell angemeldeten Benutzerkontos. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/admin/user/self ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "m.mustermann@websale.de", "firstName": "Max", "id": 1, "lastName": "Mustermann", "userName": "m.mustermann", "permissions": { "admin": { "0": false }, "newsletter": { "0": true, "1": true, "2": true, "3": true } }, "role": ["marketing"] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 404 Not Found | | Das Konto wurde in der Datenbank nicht gefunden. | ### GET admin/user/\{accountId} Dieser Endpunkt lädt die Daten eines bestimmten Benutzerkontos anhand der `accountId`. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/admin/user/123456 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "m.mustermann@websale.de", "firstName": "Max", "id": 1, "lastName": "Mustermann", "userName": "m.mustermann", "permissions": { "admin": { "0": false }, "newsletter": { "0": true, "1": true, "2": true, "3": true } }, "role": ["marketing"] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | --------------- | -------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Benutzern. | | 400 Bad Request | "invalidFormat" | `accountId` ist ungültig. | | 400 Bad Request | "invalidValue" | `accountId` ist 0. | | 404 Not Found | | Das Konto wurde in der Datenbank nicht gefunden. | ### GET admin/permissions Dieser Endpunkt gibt eine Liste mit allen Berechtigungen, die ein Benutzer haben kann. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/admin/permissions ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "id": "strapi", "permissions": [ { "id": 0, "name": "read" } ] }, { "id": "logs", "permissions": [ { "id": 0, "name": "read" }, { "id": 1, "name": "write" }, { "id": 2, "name": "create" }, { "id": 3, "name": "delete" } ] }, { "id": "blacklist", "permissions": [ { "id": 0, "name": "write" }, { "id": 1, "name": "delete" } ] }, ... ] } ``` ### POST admin/user Dieser Endpunkt erstellt ein neues Benutzerkonto für das Admin Interface. Beim Erstellen kann entweder direkt ein Passwort gesetzt oder eine E-Mail mit einem Link zum Passwortsetzen versendet werden. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/admin/user ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "m.mustermann@websale.de", "firstName": "Max", "lastName": "Mustermann", "permissions": { "admin": { "0": false }, "newsletter": { "0": true, "1": true, "2": true, "3": true } }, "role": ["marketing"], "passwordEmail": true } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": 42, "role": ["marketing"], "firstName": "Max", "lastName": "Mustermann", "email": "m.mustermann@websale.de", "permissions": {...} } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidFormat" | `firstName`, `lastName`, `email` oder `password` sind keine Strings.
    `passwordEmail` ist kein Boolean.
    `role` ist kein Array.
    `permissions` ist kein JSON-Objekt | | 400 Bad Request | "missing" | `email` oder `permissions` fehlen.
    `password` fehlt (wenn `passwordEmail` nicht auf `true` gesetzt ist). | | 400 Bad Request | "invalidCombination" | Ein Passwort ist angegeben, obwohl `passwordEmail` auf `true` gesetzt ist. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde gesendet. | | 503 Service Unavailable | "internalError" | E-Mail konnte nicht gesendet werden. | ### POST admin/passwordChange Dieser Endpunkt ändert das Passwort des aktuell angemeldeten Benutzerkontos. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/admin/passwordChange ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "newPassword": , "newPasswordAgain": , "oldPassword": } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "missing" | `newPassword`, `newPasswordAgain` oder `oldPassword` fehlen. | | 400 Bad Request | "invalidValue" | `newPassword` und `newPasswordAgain` stimmen nicht überein.
    `newPassword` ist kürzer als 12 Zeichen oder zu schwach.
    `oldPassword` stimmt nicht mit dem Passwort des Kontos überein.
    `newPassword`, `newPasswordAgain` oder `oldPassword` sind leere Strings. | | 400 Bad Request | "invalidFormat" | `newPassword`, `newPasswordAgain` oder `oldPassword` sind keine Strings. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde gesendet. | | 401 Unauthorized | | Nicht autorisiert: Sie verfügen nicht über die erforderlichen Schreibrechte. | | 403 Forbidden | | Das Konto ist gesperrt. | ### POST admin/resend/\{accountId} Dieser Endpunkt versendet eine E-Mail mit einem Link zum Zurücksetzen des Passworts an die E-Mail-Adresse, die zum Benutzerkonto gehört. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/admin/resend/9 ``` #### Request Body ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": 9, "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die Administratorrechte. | | 400 Bad Request | "invalidFormat" | `accountId` ist keine Ganzzahl. | | 400 Bad Request | "invalidValue" | `accountId` ist 0. | | 404 Not Found | | Das Konto wurde nicht gefunden. | | 503 Service Unavailable | "internalError" | Die E-Mail konnte nicht versendet werden. | ### PUT admin/user/\{accountId} Dieser Endpunkt aktualisiert die Informationen eines Benutzerkontos anhand der `accountId`. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/admin/user/123456 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "m.mustermann@websale.de", "firstName": "Max", "lastName": "Mustermann", "permissions": { "admin": { "0": false }, "newsletter": { "0": true, "1": true, "2": true, "3": true } }, "role": ["marketing"] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": 42, "role": ["marketing"], "firstName": "Max", "lastName": "Mustermann", "email": "m.mustermann@websale.de", "permissions": {...} } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidFormat" | `accountId` ist ungültig.
    `firstName`, `lastName` oder `email` sind keine Strings.
    `role` ist kein Array.
    `permissions` ist kein JSON-Objekt | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde gesendet. | | 404 Not Found | | Das Konto wurde nicht gefunden. | ### DELETE admin/user/\{accountId} Dieser Endpunkt löscht ein bestehendes Benutzerkonto anhand der `accountId`. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/admin/user/123456 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte.
    Ein Konto, das der Websale AG gehört, darf nicht gelöscht werden. | | 400 Bad Request | "invalidFormat" | `accountId` ist ungültig. | | 400 Bad Request | "invalidValue" | `accountId` ist 0. | | 404 Not Found | | Das Konto wurde nicht gefunden. | ## Methoden für Benutzereinstellungen Der Endpunkt `/admin/settings` ermöglicht das Speichern und Abrufen benutzerbezogener Einstellungen. ### GET admin/settings Dieser Endpunkt lädt die aktuellen Einstellungen des aktuell angemeldeten Benutzers, wie Sprache, Name und Dashboard-Konfiguration. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/admin/settings ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "dashboard": { "content": [ { "position": { "cols": 2, "rows": 2, "x": 0, "y": 0 }, "settings": { "timeBetweenReloads": -1 }, "widgetId": "salesToday" } ] }, "colorScheme": "light", "firstName": "Max", "language": "deu", "lastName": "Mustermann", "salutation": "m" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ------------- | ------- | --------------------------------------------------------------- | | 404 Not Found | | Es gibt keine gespeicherten Einstellungen für das aktive Konto. | ### PUT admin/settings Dieser Endpunkt aktualisiert die Benutzereinstellungen. Nicht übergebene Parameter behalten ihren bisherigen Wert. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/admin/settings ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "dashboard": { "content": [ { "position": { "cols": 2, "rows": 2, "x": 0, "y": 0 }, "settings": { "timeBetweenReloads": -1 }, "widgetId": "salesToday" } ] }, "colorScheme": "light", "firstName": "Max", "language": "deu", "lastName": "Mustermann", "salutation": "m" } ``` #### Antwort ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "missing" | `dashboard.content`, `dashboard.content.widgetId`, `dashboard.content.position`, `dashboard.content.position.cols`, `dashboard.content.position.rows`, `dashboard.content.position.x` oder `dashboard.content.position.y` fehlen. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde gesendet. | | 400 Bad Request | "invalidFormat" | `dashboard` ist kein JSON-Objekt.
    `salutation`, `language`, `colorScheme`, `firstName` oder `lastName` sind keine Strings. | | 400 Bad Request | "invalidValue" | `salutation` ist kein gültiger Wert (erlaubt: `m`, `w`, `d`). | | 401 Unauthorized | | Nicht autorisiert: Sie verfügen nicht über die erforderlichen Schreibrechte. | | 404 Not Found | | Es gibt keine gespeicherten Einstellungen für das aktive Konto. | | 503 Service Unavailable | "internalError" | Das Speichern ist fehlgeschlagen. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Bestellungen Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-bestellungen Bestellungen über die Admin Interface API abrufen, ihren Bearbeitungs- und Zahlungsstatus aktualisieren sowie einzelne Bestellungen löschen. Der Endpunkt `orders/` stellt Ihnen eine Schnittstelle zur Verwaltung von Bestelldaten in unserem Shop-System bereit. Mit dieser Schnittstelle können Sie Bestelldaten abrufen, löschen und den Status aktualisieren. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | ---------------- | ------------- | --------------------- | --------------------- | ------------------- | --------------------- | | **Bestellungen** | orders/ | | | | | ## Datenfelder einer Bestellung | **Name** | **Typ** | **Bedeutung** | | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **createdAt** | String | Zeitpunkt, zu dem die Bestellung aufgegeben wurde (ISO 8601-Format, UTC). | | **updatedAt** | String | Zeitpunkt der letzten Änderung (ISO 8601-Format, UTC).
    Nur in der Listenansicht enthalten. | | **payedAt** | String | Zeitpunkt der Bezahlung (ISO 8601-Format, UTC).
    Nur in der Listenansicht enthalten. | | **isImported** | Boolean | Gibt an, ob die Bestellung importiert wurde.
    Nur in der Listenansicht enthalten. | | **deleted** | Boolean | Gibt an, ob die Bestellung gelöscht wurde. | | **deliveryStatus** | Objekt | Informationen über den Versand | | **id** | String | Eindeutige ID der Bestellung. | | **paymentStatus** | Integer | Status der Bezahlung (z. B. offen, bezahlt, fehlgeschlagen)
    Mögliche Werte:
    0 = `Pending`
    1 = `Finished`
    2 = `Error`
    3 = `Redirected`
    4 = `CanceledByUser`
    5 = `Rejected`
    6 = `CanceledByAdmin`
    7 = `Refunded`
    8 = `RefundedPartially`
    | | **processingStatus** | Integer | Status der Bestellverarbeitung
    Mögliche Werte:
    0 = `New`
    1 = `Finished`
    2 = `Deleted`
    3 = `Canceled` | | **verificationStatus** | Integer | Status der Echtheit der Bestellung (z. B. echt, Testbestellung)
    Mögliche Werte:
    0 = `Default`
    1 = `Test`
    2 = `Fake` | | **verificationComment** | Objekt | Kommentar zur Verifizierung der Bestellung. Enthält optional die Felder `title` (String) und `comment` (String). | | **subshopId** | String | ID des Subshops, über den die Bestellung abgeschlossen wurde. | | **data.general.dateTime** | String | Zeitpunkt der Bestellung laut Metadaten (ISO 8601-Format, UTC). | | **data.general.orderId** | String | Eindeutige ID der Bestellung. | | **data.general.sessionId** | String | ID der Session, in der die Bestellung abgeschlossen wurde. | | **data.general.shopId** | String | Technischer Name des Shops. | | **data.general.shopLanguage** | String | Sprache des Shops während der Bestellung. | | **data.general.subshopId** | String | Subshop-ID aus Metadaten (redundant mit oberem Feld). | | **data.general.testMode** | Boolean | Gibt an, ob die Bestellung im Testmodus erstellt wurde. | | **data.customer.accountId** | Integer | ID des Kundenkontos, das die Bestellung getätigt hat. | | **data.customer.accountType** | String | Typ des Kundenkontos.
    Mögliche Werte:
    `"new"`
    `"registered"`
    `"guest"` | | **data.customer.customerNumber** | String | Kundennummer (sofern vergeben). | | **data.customer.deviceType** | Integer | Gerätetyp des Kunden beim Checkout. `1` – Desktop, `2` – Handy, `3` – Tablet. | | **data.customer.email** | String | E-Mail-Adresse des Kunden. | | **data.customer.ipAddress** | String | IP-Adresse des Kunden bei der Bestellung. | | **data.customer.platformType** | Integer | Plattformtyp des Kunden. `1` – Web, `2` – App. | | **data.shippingAddress** | Objekt ([**Adresse**](/schnittstellen/admin-interface-api/api-referenz-kundendaten#4-methoden-für-adressen-und-bankdaten)) | Lieferadresse | | **data.billAddress** | Objekt ([**Adresse**](/schnittstellen/admin-interface-api/api-referenz-kundendaten#4-methoden-für-adressen-und-bankdaten)) | Rechnungsadresse | | **data.order.currencyIso** | String | ISO-Code der Währung (z. B. EUR). | | **data.order.currencySymbol** | String | Währungssymbol (z. B. €). | | **data.order.defaultTaxRate** | String | Standard-Mehrwertsteuersatz. | | **data.order.delivererId** | String | ID des Versanddienstleisters. | | **data.order.delivererOrderText** | String | Anzeigename des Versanddienstleisters. | | **data.order.deliveryCost** | String | Versandkosten (Brutto). | | **data.order.deliveryTaxRate** | String | Mehrwertsteuersatz auf Versand. | | **data.order.paymentId** | String | ID der gewählten Zahlungsart. | | **data.order.paymentOrderText** | String | Anzeigename der Zahlungsart. | | **data.order.priceType** | String | Preisangabe: "gross" oder "net". | | **data.order.referer** | String | Ursprungs-URL der Bestellung. | | **data.order.subreferer** | String | Weitere Herkunftsinformationen. | | **data.order.subtotal** | String | Zwischensumme der Produkte. | | **data.order.tax** | String | Gesamtsumme der Steuern. | | **data.order.total** | String | Gesamtsumme der Bestellung (inkl. Versand und Rabatte). | | **data.order.totalCommission** | String | Gesamte Provision. | | **data.order.totalDiscount** | String | Gesamter Rabattbetrag. | | **data.order.totalVoucher** | String | Gesamter eingelöster Gutscheinwert. | | **data.order.totalWeight** | number | Gesamtgewicht der Bestellung. | | **data.orderList.item\[].basketId** | String | ID des Warenkorbeintrags. | | **data.orderList.item\[].discount** | String | Rabatt auf diesen Artikel. | | **data.orderList.item\[].extraFields** | Objekt | Benutzerdefinierte Felder des Warenkorbartikels. | | **data.orderList.item\[].isAutoBasket** | Boolean | Artikel automatisch in den Warenkorb gelegt. | | **data.orderList.item\[].isChangeable** | Boolean | Warenkorbartikel änderbar. | | **data.orderList.item\[].isRemovable** | Boolean | Warenkorbartikel entfernbar. | | **data.orderList.item\[].isVisible** | Boolean | Gibt an, ob der automatisch gelegte Artikel im Warenkorb sichtbar ist. | | **data.orderList.item\[].itemNumber** | String | Artikelnummer. | | **data.orderList.item\[].name** | String | Artikelbezeichnung. | | **data.orderList.item\[].orgPrice** | String | Originalpreis (vor Rabatt). | | **data.orderList.item\[].price** | String | Preis pro Stück. | | **data.orderList.item\[].productId** | String | Produkt-ID. | | **data.orderList.item\[].quantity** | String | Bestellte Menge. | | **data.orderList.item\[].singleTotal** | String | Gesamtpreis dieses Artikels (Menge × Preis). | | **data.orderList.item\[].taxId** | String | Steuer-ID. | | **data.orderList.item\[].taxRate** | String | Mehrwertsteuersatz. | | **data.orderList.item\[].total** | String | Endpreis dieses Artikels (inkl. Rabatt etc.). | | **data.orderList.item\[].variantId** | String | Varianten-ID. | | **data.orderList.item\[].variantSelection\[]** | Objekt\[] | Varianten-Auswahl des Artikels. | | **data.orderList.item\[].variantSelection\[].attributeId** | String | Name der Varianten-Eigenschaft (z. B. "Size"). | | **data.orderList.item\[].variantSelection\[].optionId** | String | Gewählte Option (z. B. "M"). | | **data.orderList.item\[].weight** | Float | Gewicht des Artikels. | | **data.freeFields** | Objekt | Benutzerdefinierte Felder der Bestellung | | **data.vouchers\[].id** | String | Gutschein-Code. | | **data.vouchers\[].name** | String | Name des Gutscheins. | | **data.vouchers\[].charge** | String | ID der Gutschein-Charge. | | **data.vouchers\[].value** | String | Ursprünglicher Gutscheinwert. | | **data.vouchers\[].rest** | String | Restwert des Gutscheins nach Einlösung. | | **data.vouchers\[].taxId** | String | Steuer-ID für Gutschein. | | **data.vouchers\[].taxRate** | Float | Steuersatz für Gutschein. | ### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-04-16T13:02:43Z", "data": { "billAddress": { "additionalInfo": "", "addressType": "1", "businessFax": "", "businessPhone": "", "city": "asdf", "company": "WEBSALE AG", "country": "DE", "countryName": "Deutschland", "custom": null, "dateOfBirth": "", "department": "", "fax": "", "firstName": "asdff", "lastName": "asdf", "mobilePhone": "", "phone": "987", "salutationCode": "1", "salutationText": "Herr", "state": "", "street": "asdf", "streetNumber": "9", "taxId": "", "titleCode": "2", "titleText": "Dr.", "zip": "99999" }, "computop-hosted": {}, "customer": { "accountId": 1, "accountType": "registered", "customerNumber": "", "deviceType": 1, "email": "root@root.root", "ipAddress": "172.18.0.1", "platformType": 1 }, "dummy": {}, "freeFields": { "agb.checked": "true", "agb.merchantText": "agb text here", "comment.text": "" }, "general": { "dateTime": "2025-04-16T13:02:43Z", "orderId": "1300", "sessionId": "d25e2c0b739aacdf4d3e55727ea6ffae943ebf15021ac1d6b60ba5f5c5d04582", "shopId": "", "shopLanguage": "Deutsch", "subshopId": "deutsch", "testMode": false }, "order": { "currencyIso": "EUR", "currencySymbol": "€", "defaultTaxRate": "0.1900000", "delivererId": "hermes", "delivererOrderText": "Hermes", "deliveryCost": "3.95", "deliveryTaxRate": "0.1900000", "paymentId": "safepayment", "paymentOrderText": "Sichere Zahlungsart", "priceType": "gross", "referer": "https://myshop.localhost/?wsvc=View&view=confirm.htm", "subreferer": "", "subtotal": "10.00", "tax": "0.63", "total": "3.95", "totalCommission": "0.00", "totalDiscount": "0.00", "totalVoucher": "10.00", "totalWeight": 0 }, "orderList": { "item": [ { "basketId": "9680cda2830c10b063ca", "discount": "0.00", "extraFields": {}, "isAutoBasket": false, "isChangeable": true, "isRemovable": true, "isVisible": true, "itemNumber": "8765", "name": "Something2", "orgPrice": "0.00", "price": "5.00", "productId": "143-68071", "quantity": "1.00", "singleTotal": "5.00", "taxId": "19", "taxRate": "0.1900000", "total": "5.00", "variantId": "", "variantSelection": null, "weight": 0 }, { "basketId": "0d191c832e46f326fc420dc59aa9facfc69f2fda5a5cad2e26d...", "discount": "0.00", "extraFields": {}, "isAutoBasket": true, "isChangeable": false, "isRemovable": false, "isVisible": true, "itemNumber": "12341234", "name": "myProduct", "orgPrice": "0.00", "price": "5.00", "productId": "105-59442", "quantity": "1.00", "singleTotal": "5.00", "taxId": "19", "taxRate": "0.1900000", "total": "5.00", "variantId": "1", "variantSelection": [ { "attributeId": "Color", "optionId": "red" }, { "attributeId": "Size", "optionId": "M" } ], "weight": 0 } ] }, "paypal-checkout": { "executePayPalResponse": "", "expressCheckout": "false", "orderID": "", "paymentAction": "CAPTURE", "paymentID": "", "paymentMode": "PayPal", "paypalStatus": "" }, "shippingAddress": null, "vouchers": [ { "charge": "121", "id": "93JC-TGGL-KA3M-MRA7", "name": "myVoucher", "rest": "0.00", "taxId": "19", "taxRate": 0.19, "value": "55.00" } ] }, "deleted": false, "deliveryStatus": {}, "id": "1300", "paymentStatus": 1, "processingStatus": 0, "subshopId": "deutsch", "verificationComment": {}, "verificationStatus": 0 } ``` ## Verwendung der Methoden ### GET orders Diese Methode liefert eine Liste aller Bestellungen aus dem Admin-Interface des Shops. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/orders ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "accountId": 1, "createdAt": "2024-11-07T17:38:32Z", "data": { "billAddress": { "country": "DE", "countryName": "Deutschland", "firstName": "asdf", ... }, "computop-hosted": {}, "customer": { "accountId": 1, "accountType": "registered", "email": "root@root.root", "ipAddress": "172.18.0.1" }, "dummy": {}, "freeFields": { "agb.checked": "true", "agb.merchantText": "agb text here", "comment.text": "" }, "general": { "dateTime": "2024-11-07T17:38:32Z", "orderId": "820", "sessionId": "79d803076669c8a41874d9d2cd8451f...", "shopId": "myshop", "shopLanguage": "", "subshopId": "deutsch", "testMode": false }, "order": { "currencyIso": "EUR", "currencySymbol": "€", "defaultTaxRate": "0.1900000", "delivererId": "dhl", "delivererOrderText": "DHL", "deliveryCost": "11.00", "deliveryTaxRate": "0.1900000", "paymentId": "bill", "paymentOrderText": "Rechnung", "priceType": "gross", "subtotal": "5.00", "tax": "2.55", "total": "16.00", "totalCommission": "0.00", "totalDiscount": "0.00", "totalVoucher": "0.00" }, "orderList": { "item": [ { "basketId": "d0c04a4cb60f708288a2", "freeFields": { "gravur1": "", "gravur2": "", "gravur3": "" }, "isAutoBasket": false, "isChangeable": true, "isRemovable": true, "isVisible": true, "itemNumber": "8", "name": "T-Shirt 'Land Rover' in Hellgrau", "price": "5.00", "productId": "105-59442", "quantity": "1.00", "singleTotal": "5.00", "taxId": "19", "taxRate": "0.1900000", "total": "5.00", "variantId": "1", "variantSelection": [ { "attributeId": "555", "optionId": "foo" }, { "attributeId": "888", "optionId": "bar" } ] } ] }, "paypal-checkout": { "executePayPalResponse": "", "orderID": "", "paymentAction": "CAPTURE", "paymentID": "", "paymentMode": "PayPal", "paypalStatus": "" }, "shippingAddress": null, "vouchers": null }, "deleted": false, "deliveryStatus": {}, "id": "820", "isImported": false, "payedAt": "2024-11-07T17:38:32Z", "paymentStatus": 1, "processingStatus": 0, "subshopId": "deutsch", "updatedAt": "2024-11-07T17:38:32Z", "verificationComment": {}, "verificationStatus": 0, "version": 1 }, ... ], "nextPageToken": "Mw", "totalCount": 4 } ``` #### Filterfelder `createdAt`, `updatedAt`, `payedAt`, `id`, `subshopId`, `accountId`, `processingStatus`, `paymentStatus`, `verificationStatus`, `deleted` #### Sortierfelder `createdAt`, `updatedAt`, `id`, `processingStatus`, `paymentStatus`, `subshopId` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------- | -------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Benutzern. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | | 503 Service Unavailable | "internalError" | Nicht alle Bestellungen konnten entschlüsselt werden. | ### GET orders/\{orderId} Diese Methode ruft die Details einer einzelnen Bestellung anhand ihrer eindeutigen Bestell-ID ab. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/orders/860 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2024-11-08T14:36:30Z", "data": { "billAddress": { "businessFax": "", "businessPhone": "", "city": "asdf", "company": "", "country": "DE", "countryName": "Deutschland", "custom": null, "dateOfBirth": "", "department": "", "fax": "", "firstName": "asdf", "lastName": "asdf", "mobilePhone": "", "phone": "987", "salutationCode": "1", "salutationText": "Herr", "state": "", "street": "asdf", "streetNumber": "9", "taxId": "", "titleCode": "", "zip": "99999" }, "computop-hosted": {}, "customer": { "accountId": 1, "accountType": "registered", "email": "root@root.root", "ipAddress": "172.18.0.1" }, "dummy": {}, "freeFields": { "agb.checked": "true", "agb.merchantText": "agb text here", "comment.text": "" }, "general": { "dateTime": "2024-11-08T14:36:30Z", "orderId": "860", "sessionId": "16be344c872261602e84cd0116e0b7a11a...", "shopId": "myshop", "shopLanguage": "", "subshopId": "deutsch", "testMode": false }, "order": { "currencyIso": "EUR", "currencySymbol": "€", "defaultTaxRate": "0.1900000", "delivererId": "dhl", "delivererOrderText": "DHL", "deliveryCost": "11.00", "deliveryTaxRate": "0.1900000", "paymentId": "prepayment", "paymentOrderText": "Vorauskasse", "priceType": "gross", "subtotal": "8.00", "tax": "1.76", "total": "19.00", "totalCommission": "0.00", "totalDiscount": "0.00", "totalVoucher": "0.00" }, "orderList": { "item": [ { "basketId": "01ddd733642b89429105", "isAutoBasket": false, "isChangeable": true, "isRemovable": true, "isVisible": true, "itemNumber": "123456", "name": "Tartan-Langarm-Polo in Navy", "price": "8.00", "productId": "106-19021", "quantity": "1.00", "singleTotal": "8.00", "taxId": "zero", "taxRate": "0.0000000", "total": "8.00", "variantId": "", "variantSelection": null } ] }, "paypal-checkout": { "executePayPalResponse": "", "orderID": "", "paymentAction": "CAPTURE", "paymentID": "", "paymentMode": "PayPal", "paypalStatus": "" }, "shippingAddress": null, "vouchers": null }, "deleted": false, "deliveryStatus": {}, "id": "860", "paymentStatus": 1, "processingStatus": 0, "subshopId": "deutsch", "verificationComment": {}, "verificationStatus": 0 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | --------------------------------------------------------------------------------- | | 401 Unauthorized | | Man ist kein Administrator und hat keine Berechtigung zum Lesen von Bestelldaten. | | 404 Not Found | | Die Bestellung wurde nicht gefunden. | | 400 Bad Request | "missing" | `orderId` fehlt. | | 503 Service Unavailable | "internalError" | Die Bestellung konnte nicht geladen oder nicht entschlüsselt werden. | ### PUT orders/\{orderId} Diese Methode aktualisiert eine bestehende Bestellung anhand ihrer eindeutigen Bestell-ID. Alle Felder sind optional. Das Feld `deliveryStatus` soll ein als String serialisiertes Objekt sein. Die Felder `verificationComment` (String) und `verificationTitle` (String) werden nur bei Änderung des `verificationStatus` ausgewertet. Bei jeder Änderung des Verification-Status wird automatisch ein Log-Eintrag mit dem Log-Level `Info` und der Message-ID `order.updateVerificationStatusSuccess` erzeugt. Werte für `processingStatus`: `0 = New`\ `1 = Finished`\ `2 = Deleted`\ `3 = Canceled` Werte für `verificationStatus`: `0 = Default`\ `1 = Test`\ `2 = Fake`\\ #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/orders/188 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "processingStatus": 3, "verificationStatus": 2, "verificationComment": "Mein Kommentar", "verificationTitle": "Mein Titel", "deliveryStatus": "{\"type\":\"global\",\"statusType\":\"tracking\",\"data\":{\"trackingVendorId\":\"\",\"trackingNumber\":\"12345\"}}" } ``` #### Antwort Bei Erfolg wird die aktualisierte Bestellung zurückgegeben (gleiches Format wie bei GET orders/\{orderId}). ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "188", "subshopId": "deutsch", "data": { ... }, "createdAt": "2025-04-16T13:02:43Z", "processingStatus": 3, "paymentStatus": 1, "deleted": false, "deliveryStatus": { ... }, "verificationComment": {}, "verificationStatus": 2 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Benutzern. | | 400 Bad Request | | Request body konnte nicht geladen werden.
    Das Aktualisieren ist fehlgeschlagen. | | 400 Bad Request | "unknownDataField" | Es wird versucht, ein unbekanntes Feld zu aktualisieren. Erlaubte Felder: `processingStatus`, `verificationStatus`, `deliveryStatus`, `verificationComment`, `verificationTitle`. | | 400 Bad Request | "invalidFormat" | `processingStatus` ist keine Zahl. `verificationStatus` ist keine Zahl. `deliveryStatus`, `verificationComment` oder `verificationTitle` ist kein String. | | 400 Bad Request | "invalidValue" | `processingStatus` ∉ \[0;3]
    `verificationStatus` ∉ \[0;2] | | 400 Bad Request | "illegalOperation" | | | | 404 Not Found | | | 503 Service Unavailable | "internalError" | Die Bestellung konnte nach dem Aktualisieren nicht neu geladen werden. | ### DELETE orders/\{orderId} Diese Methode löscht eine bestehende Bestellung anhand ihrer eindeutigen Bestell-ID. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/orders/265 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ----------------------------------------------------------------------------------- | | 401 Unauthorized | | Man ist kein Administrator und hat keine Berechtigung zum Löschen von Bestelldaten. | | 400 Bad Request | "missing" | `orderId` fehlt. | | 404 Not Found | | Die Bestellung wurde nicht gefunden. | | 503 Service Unavailable | "internalError" | Die Bestellung konnte nicht geladen oder nicht entschlüsselt werden. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Bildkonverter Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-bildkonverter Produkt- und Kategoriebilder über die Admin Interface API hochladen, konvertieren, löschen und die zugehörigen Bild-URLs abfragen. Die Schnittstelle unter `/images/` bietet Ihnen umfassende Funktionen zur Verwaltung von Bildern unterschiedlicher Formate in unserem Shopsystem. Über verschiedene Endpunkte können Sie Bilder hochladen, konvertieren, löschen sowie die zugehörigen URLs abrufen. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | ---------------- | ------------- | --------------------- | ------------------- | --------------------- | --------------------- | | **Image Upload** | images/ | | | | | ## Unterstützte Bildformate * `Bitmap` * `FITS` * `GIF` * `Graphics Kernel System` * `JPEG` * `NIFF` * `PM` * `PNG` * `XFIG` * `XPM` * `TIFF` * `GIMP XCF` * `webp` * `AVIF` ## Datenfelder eines Verzeichnisses | **Name** | **Typ** | **Verwendung** | | ------------------ | ------- | --------------------------------- | | **name** | String | Der Name des Verzeichnisses | | **path** | String | Der Pfad zum Verzeichnis | | **subDirectories** | Array | Ein Array von Unterverzeichnissen | ### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "products", "path": "products", "subDirectories": [ { "name": "thumbnail", "path": "products/thumbnail", "subDirectories": [] }, { "name": "normal", "path": "products/normal", "subDirectories": [] }, { "name": "large", "path": "products/large", "subDirectories": [] } ] } ``` ## Methoden zur Verwaltung von Bildern ### GET images/url/\{typeId} ### GET images/url/\{typeId} Dieser Endpunkt liefert die URL eines Bildes basierend auf dem angegebenen Typ (`typeId`) und optional dem gewünschten Format. Er wird verwendet, um den Speicherort eines Bildes im System zu ermitteln – insbesondere, wenn der Pfad nach dem Hochladen nicht bekannt ist.\ Gültige Werte für `typeId` sind: * `categories` für Kategoriebilder, * `products` für Produktbilder, * `appImages` für Bilder innerhalb der App-Oberfläche. Die zurückgegebene URL zeigt auf das Zielverzeichnis für den jeweiligen Bildtyp, sodass anschließend Bilddaten korrekt abgelegt oder referenziert werden können. Leseberechtigungen sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/images/url/products?formatNodeId=content.imageFormat.normal ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true, "url": "//content..de" } ``` | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ---------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Kategorie-, Produkt- oder App-Daten. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "missing" | `subshopId` oder `formatNodeId` wurden nicht übergeben. | ### GET images/directories/\{typeId} ### GET images/directories/\{typeId} Dieser Endpunkt liefert die Struktur der verfügbaren Bildverzeichnisse als Baumstruktur zurück. Je nach Wert des Parameters `typeId` werden entweder Quellverzeichnisse (`source`) oder Zielverzeichnisse (`target`) ausgegeben. Die Antwort enthält eine hierarchische Darstellung der vorhandenen Ordner und Unterordner. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/images/directories/source ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "name": "myDir1", "path": "myDir1", "subDirectories": [ { "name": "myDir2", "path": "myDir1/myDir2", "subDirectories": [] }, { "name": "myDir3", "path": "myDir1/myDir3", "subDirectories": [ { "name": "myDir4", "path": "myDir1/myDir3/myDir4", "subDirectories": [] } ] } ] } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | -------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von konvertierten Bildern. | | 400 Bad Request | "invalidValue" | | ### GET images/convert/results Dieser Endpunkt liefert eine paginierte Liste der Ergebnisse abgeschlossener Bildkonvertierungen. Für jedes konvertierte Bild werden Informationen wie Quelldatei, Zieldatei, Zielformat, Dateigröße, Dauer der Konvertierung und der Verarbeitungsstatus zurückgegeben. So kann nachvollzogen werden, ob und wie ein Bild erfolgreich in verschiedene Formate umgewandelt wurde. #### Query-Parameter | **Name** | **Typ** | **Verwendung** | | ------------- | ----------------- | ----------------------------------------------------------------------------------- | | **size** | Number (optional) | Anzahl der Ergebnisse pro Seite. Standardwert wird verwendet, wenn nicht angegeben. | | **pageToken** | String (optional) | Token für die nächste Seite. Wird in der Antwort als `nextPageToken` zurückgegeben. | #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/images/convert/results?size=200 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "duration": 0, "fileSize": "55 KB", "format": "app", "formatId": "content.imageFormat.app", "message": "success", "output": "app/Screenshot 2025-03-24 222742.png", "outputFilename": "Screenshot 2025-03-24 222742.png", "source": "upload/9fcd26d4c240/Screenshot 2025-03-24 222742.png", "sourceFilename": "Screenshot 2025-03-24 222742.png", "status": "success" }, { "duration": 1, "fileSize": "55 KB", "format": "normal category", "formatId": "content.imageFormat.normalCategory", "message": "success", "output": "categories/normal/Screenshot 2025-03-24 222742.png", "outputFilename": "Screenshot 2025-03-24 222742.png", "source": "upload/9fcd26d4c240/Screenshot 2025-03-24 222742.png", "sourceFilename": "Screenshot 2025-03-24 222742.png", "status": "success" }, { "duration": 1, "fileSize": "55 KB", "format": "normal product", "formatId": "content.imageFormat.normalProduct", "message": "success", "output": "products/normal/Screenshot 2025-03-24 222742.png", "outputFilename": "Screenshot 2025-03-24 222742.png", "source": "upload/9fcd26d4c240/Screenshot 2025-03-24 222742.png", "sourceFilename": "Screenshot 2025-03-24 222742.png", "status": "success" }, { "duration": 1, "fileSize": "10 KB", "format": "thumbnail product", "formatId": "content.imageFormat.thumbnailProduct", "message": "success", "output": "products/thumbnail/Screenshot 2025-03-24 222742.png", "outputFilename": "Screenshot 2025-03-24 222742.png", "source": "upload/9fcd26d4c240/Screenshot 2025-03-24 222742.png", "sourceFilename": "Screenshot 2025-03-24 222742.png", "status": "success" } ], "totalCount": 4, "endReached": true, "nextPageToken": "MjAw" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | -------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von konvertierten Bildern. | ### GET images/convert/status Dieser Endpunkt liefert den aktuellen Status eines laufenden oder den letzten bekannten Status eines abgeschlossenen Bildkonvertierungsprozesses. Dabei werden Informationen wie Fortschritt, Anzahl erfolgreicher oder fehlgeschlagener Konvertierungen, sowie Timer-Daten (Startzeit, Endzeit, Dauer) zurückgegeben. Der Endpunkt ermöglicht die Überwachung und Auswertung von Bildkonvertierungsprozessen im System. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/images/convert/status ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "canceled": true, "counter": { "error": 0, "skipped": 0, "success": 0, "warning": 0 }, "formatCounter": { "error": 0, "skipped": 0, "success": 0, "warning": 0 }, "progress": { "finished": 0, "percentage": 0, "total": 0 }, "progressFormat": { "finished": 0, "percentage": 0, "total": 0 }, "running": false, "status": "ready", "timer": { "duration": 0, "end": 0, "start": 0 }, "usedFormats": [] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | -------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von konvertierten Bildern. | | 503 Service Unavailable | "internalError" | Der Konvertierungsprozess kann nicht geprüft werden. | ### GET images/report/products Dieser Endpunkt liefert einen Bericht über die Nutzung von Produktbildern im Shopsystem. Dabei werden sowohl fehlende Bilder (`missingImages`) als auch ungenutzte Bilder (`unusedImages`) aufgelistet. Der Bericht hilft dabei, Bilddateien zu identifizieren, die keinem aktiven Produkt mehr zugeordnet sind oder die im System fehlen, und unterstützt so bei der Optimierung der Bilddatenverwaltung. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/images/report/products ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-04-25T15:55:39.000Z", "id": 1, "missingImages": [], "unusedImages": [ { "filename": "th.jpg", "format": "" }, { "filename": "Screenshot 2025-03-24 222742.png", "format": "" }, { "filename": "th.jpg", "format": "" }, { "filename": "Screenshot 2025-03-24 222742.png", "format": "" } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ----------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Produktdaten. | ### POST images/upload Dieser Endpunkt ermöglicht das Hochladen eines Bildes in das Shopsystem. Das Bild wird als Base64-kodierter String im Request-Body übertragen. Zusätzlich kann angegeben werden, in welche Formate das Bild konvertiert werden soll. Nach dem erfolgreichen Upload wird der Pfad zur gespeicherten Bilddatei zurückgegeben. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/images/upload ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "fileName": [ "Screenshot 2025-03-24 222742.png" ], "formats": [ "content.imageFormat.normalProduct", "content.imageFormat.thumbnailProduct" ], "imageData": [ "iVBORw0KGgoAAAANSUhEUgAAAU8AAAJcCAYAAAB5ZyZaAAAAAXNSR0IArs4c6QAAAA..." ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "path": "upload/c14cb01ea580", "size": 1, "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Veröffentlichen von konvertierten Bildern. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "missing" | `formats` wurden nicht übergeben. | | 400 Bad Request | "invalidValue" | Ein Bildformat ist ungültig. `imageData` ist ungültig. | | 400 Bad Request | "invalidFormat" | Das Feld `formats` ist kein Array von Strings.
    Das Feld `fileName` ist kein String und kein Array von Strings.
    Das Feld `imageData` ist kein String und kein Array von Strings. | | 400 Bad Request | "invalidFileFormat" | Das Bild hat ein ungültiges Format. | | 400 Bad Request | "unknownDataField" | Request body enthält etwas außer `fileName`, `imageData` und `formats`. | | 503 Service Unavailable | "internalError" | Das Hochladen des Bildes ist fehlgeschlagen. | ### POST images/upload/convert Dieser Endpunkt ermöglicht das Hochladen eines Bildes mit anschließender sofortiger Konvertierung in ein oder mehrere definierte Zielformate. Das Bild wird als Base64-kodierter String im Request-Body übermittelt. Im Unterschied zum normalen Upload wird hier die Konvertierung automatisch angestoßen, sodass direkt optimierte oder formatangepasste Varianten erstellt werden können. Nach Abschluss wird eine Übersicht der erzeugten Bilddateien zurückgegeben. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/images/upload/convert ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "fileName": "myPicture.png", "formats": [ "content.imageFormat.normalCategory", "content.imageFormat.normalProduct" ], "imageData": "iVBORw0KGgoAAAANSUhEUgAAAU8AAAJcCAYAAAB5ZyZaAAAAAXNS..." } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "duration": 0, "fileSize": "55 KB", "format": "normal category", "formatId": "content.imageFormat.normalCategory", "message": "success", "output": "categories/normal/myPicture.png", "outputFilename": "myPicture.png", "source": "upload/169357275289/myPicture.png", "sourceFilename": "myPicture.png", "status": "success" }, { "duration": 0, "fileSize": "55 KB", "format": "normal product", "formatId": "content.imageFormat.normalProduct", "message": "success", "output": "products/normal/myPicture.png", "outputFilename": "myPicture.png", "source": "upload/169357275289/myPicture.png", "sourceFilename": "myPicture.png", "status": "success" } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Veröffentlichen von konvertierten Bildern. Der Bildtyp wird in den Berechtigungen berücksichtigt. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "missing" | `formats` wurden nicht übergeben. | | 400 Bad Request | "invalidValue" | Ein Bildformat ist ungültig. `imageData` ist ungültig. Es wurden mehrere Bilder übergeben. | | 400 Bad Request | "invalidFormat" | Das Feld `formats` ist kein Array von Strings.
    Das Feld `fileName` ist kein String und kein Array von Strings.
    Das Feld `imageData` ist kein String und kein Array von Strings. | | 400 Bad Request | "invalidFileFormat" | Das Bild hat ein ungültiges Format. | | 400 Bad Request | "unknownDataField" | Request body enthält etwas außer `fileName`, `imageData` und `formats`. | | 503 Service Unavailable | "internalError" | Das Konvertieren vom Bild ist fehlgeschlagen. | | 503 Service Unavailable | "serviceUnavailable" | Der Konvertierungsprozess konnte nicht gestartet werden. | ### POST images/report Dieser Endpunkt startet die Überprüfung der im System vorhandenen Bilder auf fehlende oder ungenutzte Dateien. Die Ausführung erfolgt asynchron: Nach dem erfolgreichen Start der Überprüfung wird kein direktes Ergebnis zurückgegeben. Der vollständige Bericht kann anschließend über `GET /images/report/` abgerufen werden. Der Endpunkt stellt sicher, dass Bilddaten regelmäßig auf Konsistenz geprüft werden können. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/images/report ``` #### Request Body ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------- | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Produkten. | | 503 Service Unavailable | "serviceUnavailable" | Der Überprüfung konnte nicht gestartet werden. | ### POST images/convert/start Dieser Endpunkt startet den Konvertierungsprozess für im System gespeicherte Bilder. Dabei werden die Bilder in die jeweils definierten Zielformate umgewandelt (z. B. verschiedene Größen oder Dateiformate). Die Ausführung erfolgt asynchron, aber es wird nach dem Starten vom Prozess eine direkte Rückmeldung zu den konvertierten Bildern geliefert. Der Fortschritt und der Status der Konvertierung können später über den Endpunkt `GET /images/convert/status` abgefragt werden. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/images/convert/start ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "action": "manual", "source": "directory", "formatList": [ "content.imageFormat.app", "content.imageFormat.normalCategory", "content.imageFormat.normalProduct", "content.imageFormat.thumbnailProduct" ], "directory": "upload/e6122e69f1d0" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "canceled": true, "counter": { "error": 0, "skipped": 0, "success": 0, "warning": 0 }, "formatCounter": { "error": 0, "skipped": 0, "success": 4, "warning": 0 }, "progress": { "finished": 1, "percentage": 100, "total": 1 }, "progressFormat": { "finished": 4, "percentage": 100, "total": 4 }, "running": false, "status": "finished", "timer": { "duration": 1745857938, "end": 1745857938, "start": 0 }, "usedFormats": [ "content.imageFormat.app", "content.imageFormat.normalCategory", "content.imageFormat.normalProduct", "content.imageFormat.thumbnailProduct" ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Veröffentlichen von konvertierten Bildern. | | 400 Bad Request | | Request body konnte nicht geladen werden.
    Das Format wurde nicht gefunden.
    Das Format hat ein ungültiges Quellverzeichnis oder es wurde ein ungültiges Quellverzeichnis angegeben.
    Es existieren keine Formate.
    Das Feld `source` enthält etwas außer `format` oder `directory`. | | 503 Service Unavailable | "serviceUnavailable" | Der Konvertierungsprozess konnte nicht gestartet werden. | | 503 Service Unavailable | "internalError" | Der Konvertierungsstatus kann nicht abgerufen werden. | ### POST images/convert/cancel Dieser Endpunkt bricht einen aktuell laufenden Konvertierungsprozess für Bilder ab. Der Abbruch erfolgt nicht asynchron, es wird eine direkte Rückmeldung zu den konvertierten Bildern gleich geliefert. Nach der Ausführung kann der Status des Konvertierungsprozesses über den Endpunkt `GET /images/convert/status` wieder abgefragt werden. Der Abbruchvorgang erfordert entsprechende Berechtigungen. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/images/convert/cancel ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "cancelStatus": "triggered", "canceled": true, "counter": { "error": 0, "skipped": 0, "success": 0, "warning": 0 }, "formatCounter": { "error": 0, "skipped": 0, "success": 2, "warning": 0 }, "progress": { "finished": 1, "percentage": 100, "total": 1 }, "progressFormat": { "finished": 2, "percentage": 100, "total": 2 }, "running": false, "status": "finished", "timer": { "duration": 1745858133, "end": 1745858133, "start": 0 }, "usedFormats": [ "content.imageFormat.normalProduct", "content.imageFormat.thumbnailProduct" ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Veröffentlichen von konvertierten Bildern. | | 503 Service Unavailable | "internalError" | Der Konvertierungsprozess kann nicht geprüft werden. | ### POST images/directories/\{typeId} ### POST images/directories/\{typeId} Ein Verzeichnis wird erstellt. Bei `typeId` = `source` handelt es sich um Quellverzeichnisse, bei `typeId` = `target` handelt es sich um Zielverzeichnisse. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/images/directories/target ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "path": "myDir", "name": "test" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "name": "myDir", "path": "myDir", "subDirectories": [ { "name": "test", "path": "myDir/test", "subDirectories": [] } ] } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von konvertierten Bildern. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | `name` oder `path` ist ungültig. | | 400 Bad Request | "missing" | `name` wurde nicht übergeben. | | 503 Service Unavailable | "internalError" | Das Erstellen vom Verzeichnis ist fehlgeschlagen. | ### DELETE images/directories/\{typeId} ### DELETE images/directories/\{typeId} Dieser Endpunkt löscht ein Verzeichnis innerhalb des angegebenen Bereichs (`source` oder `target`) für Bilddateien. Über den Request-Body können der Pfad zum übergeordneten Verzeichnis sowie der Name des zu löschenden Ordners definiert werden. Nach erfolgreicher Löschung wird die aktualisierte Verzeichnisstruktur ohne das gelöschte Verzeichnis als Baumstruktur zurückgegeben. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/images/directories/target ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "path": "myDir/test" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "name": "myDir", "path": "myDir", "subDirectories": [] } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von konvertierten Bildern. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | path fehlt oder ist leer. | | 404 Not Found | | Das Verzeichnis wurde nicht gefunden. | | 503 Service Unavailable | "internalError" | Das Löschen vom Verzeichnis ist fehlgeschlagen. | ### DELETE images/upload/\{typeId} ### DELETE images/upload/\{typeId} Dieser Endpunkt löscht eines oder mehrere Bilder innerhalb eines angegebenen Bereichs (`categories`, `products` oder `appImages`). Der Name der zu löschenden Datei(en) wird über das Feld `fileName` im Request-Body angegeben, entweder als String oder als Array von Strings. Optional kann über das Feld `formats` angegeben werden, welche Bildformate berücksichtigt werden sollen; andernfalls werden alle Formate gelöscht. Der Endpunkt prüft sorgfältig die Gültigkeit der angegebenen Parameter und verarbeitet sowohl Einzel- als auch Mehrfachlöschungen. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/images/upload/appImages ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "formats": [ "content.imageFormat.app" ], "fileName": "th_1740130633.jpg" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Kategorie-, Produkt- oder App-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "missing" | `subshopId` oder `fileName` wurden nicht übergeben. | | 400 Bad Request | "invalidValue" | `subshopId` ist ungültig. Ein Bildformat ist ungültig. | | 400 Bad Request | "invalidFormat" | Das Feld `formats` ist kein Array von Strings.
    Das Feld `fileName` ist kein String und kein Array von Strings. | | 400 Bad Request | "unknownDataField" | Request body enthält etwas außer `fileName` und `formats`. | | 503 Service Unavailable | "internalError" | Das Löschen von Bildern ist fehlgeschlagen. | ### DELETE images/upload/\{typeId}/\{filename} ### DELETE images/upload/\{typeId}/\{filename} Dieser Endpunkt löscht ein bestimmtes Bild innerhalb eines angegebenen Bereichs (`categories`, `products` oder `appImages`). Der zu löschende Dateiname wird direkt als Pfadparameter (`filename`) übergeben. Zusätzlich können im Request-Body weitere Dateinamen (`fileName`) angegeben werden, entweder als einzelner String oder als Array von Strings. Über das optionale Feld `formats` kann festgelegt werden, welche Bildformate gelöscht werden sollen; andernfalls werden alle Formate berücksichtigt. Der Endpunkt unterstützt sowohl die Löschung eines einzelnen Bildes als auch die kombinierte Löschung mehrerer Bilder. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/images/upload/appImages/th_1740129668.jpg ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "formats": [ "content.imageFormat.app" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Kategorie-, Produkt- oder App-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "missing" | `subshopId` oder `fileName` wurden nicht übergeben. | | 400 Bad Request | "invalidValue" | `subshopId` ist ungültig. Ein Bildformat ist ungültig. | | 400 Bad Request | "invalidFormat" | Das Feld `formats` ist kein Array von Strings.
    Das Feld `fileName` ist kein String und kein Array von Strings. | | 400 Bad Request | "unknownDataField" | Request body enthält etwas außer `fileName` und `formats`. | | 503 Service Unavailable | "internalError" | Das Löschen von Bildern ist fehlgeschlagen. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Blacklist Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-blacklist Newsletter-Blacklist über die Admin Interface API verwalten: E-Mail-Adressen vom Versand ausschließen oder Einträge wieder entfernen. Die Schnittstelle `/blacklist/` ermöglicht die Verwaltung einer Blacklist für E-Mail-Adressen, die vom Versand von Newslettern ausgeschlossen werden sollen. Über entsprechende Endpunkte können neue Einträge hinzugefügt oder bestehende gelöscht werden. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | ----------------------- | ------------- | ------------------- | --------------------- | ------------------- | ------------------- | | **Blacklist verwalten** | blacklist/ | | | | | ## Verwendung der Methoden ### POST blacklist/add Dieser Endpunkt fügt eine E-Mail-Adresse zur Blacklist hinzu. Die Adresse wird im Request-Body übermittelt und bei erfolgreicher Verarbeitung als Hash gespeichert. Die Antwort gibt an, ob die Operation erfolgreich war (`true`) oder fehlgeschlagen ist (`false`). Der Zugriff auf diesen Endpunkt erfordert ein Benutzerkonto mit entsprechenden Berechtigungen. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/blacklist/add ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "example@example.com" } ``` #### Antwort ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} true/false ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Blacklist-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "missing" | `email` wurde nicht übergeben. | | 400 Bad Request | "invalidFormat" | `email` ist kein String. | | 400 Bad Request | "invalidValue" | `email` darf nicht leer sein. | | 400 Bad Request | "unknownDataField" | Es wurde ein unbekanntes Feld übergeben. | ### POST blacklist/remove Dieser Endpunkt entfernt eine E-Mail-Adresse aus der Blacklist. Die Adresse wird im Request-Body übermittelt. Die Antwort gibt an, ob die Operation erfolgreich war (`true`) oder fehlgeschlagen ist (`false`). Der Zugriff auf diesen Endpunkt erfordert ein Benutzerkonto mit entsprechenden Berechtigungen. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/blacklist/remove ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "example@example.com" } ``` #### Antwort ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} true/false ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ---------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Blacklist-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "missing" | `email` wurde nicht übergeben. | | 400 Bad Request | "invalidFormat" | `email` ist kein String. | | 400 Bad Request | "invalidValue" | `email` darf nicht leer sein. | | 400 Bad Request | "unknownDataField" | Es wurde ein unbekanntes Feld übergeben. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz CMS Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-cms Über die Admin Interface API die URL zum angebundenen Strapi-CMS abrufen und Redakteure direkt in den Admin-Bereich des CMS leiten. Die Schnittstelle `/cms/` stellt einen Zugriffspunkt bereit, um die URL zum Strapi-Content-Management-System (CMS) des Shopsystems abzurufen. Der Endpunkt liefert den direkten Link zum Strapi-Adminbereich, sodass sich berechtigte Benutzer dort anmelden und Inhalte verwalten können. Aktuell wird ausschließlich der CMS-Typ `strapi` unterstützt. Ein direkter Zugriff auf CMS-Inhalte über die API ist derzeit nicht vorgesehen. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | --------------- | ------------- | --------------------- | ------------------- | ------------------- | ------------------- | | **CMS** | cms/ | | | | | ## Methoden für das CMS ### GET cms/ Dieser Endpunkt liefert die URL zum Adminbereich des angebundenen Content-Management-Systems (CMS). Über einen Query-Parameter kann der Typ des CMS angegeben werden; derzeit wird ausschließlich `strapi` unterstützt. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/cms?type=strapi ``` #### Antwort ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://-cms.websale.net/admin ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von CMS-Daten. | | 400 Bad Request | "invalidValue" | Der Parameter `type` fehlt oder hat einen ungültigen Wert.
    Zurzeit wird ausschließlich der Wert `strapi` unterstützt. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Datenfeeds Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-datenfeeds Produktdatenfeeds für externe Plattformen wie Suchmaschinen über die Admin Interface API anlegen, bearbeiten, planen, exportieren und löschen. Datenfeeds ermöglichen es, Produktdaten aus einem WEBSALE Shop für externe Systeme wie Suchmaschinen, Suchdienstleister etc. bereitzustellen. Der Endpunkt `datafeeds/` ermöglicht es Ihnen, Ihre Datenfeeds zu verwalten. Mit dieser Schnittstelle können Sie bereits erstellte Feeds aktualisieren und löschen oder neue Datenfeeds erstellen. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | ---------------------- | ------------------- | --------------------- | --------------------- | --------------------- | --------------------- | | **Datenfeeds** | datafeeds/ | | | | | | **Datenfeed-Vorlagen** | datafeeds/templates | | | | | | **Generierung** | datafeeds/build | | | | | ## Datenfelder eines Datenfeeds | **Name** | **Typ** | **Verwendung** | | ----------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------- | | **active** | Boolean | Gibt an, ob der Datenfeed für den Export aktiviert ist | | **createdAt** | String | Zeitpunkt, zu dem der Datenfeed angelegt wurde (ISO 8601-Format, UTC). | | **exportPlanOptions.exportAfterImport** | Boolean | Gibt an, ob der Datenfeed nach einem Importvorgang automatisch exportiert wird. | | **exportPlanOptions.exportPlan** | Array | Liste Stunden, zu denen ein Export geplant ist. | | **exportStatus** | String | Status des letzten Exports:
    `"idle"`
    `"starting"`
    `"running"`
    `"finished"`
    `"error"` | | **externalOutputTarget.host** | String | Hostname oder IP-Adresse des externen Zielsystems | | **externalOutputTarget.password** | String | Passwort für Zugriff auf das Zielsystem | | **externalOutputTarget.port** | Integer | Portnummer des externen Zielsystems (z. B. 21 für FTP) | | **externalOutputTarget.remotePath** | String | Zielverzeichnis auf dem externen Server | | **externalOutputTarget.type** | String | Typ des Zielsystems (z. B. „ftp“, „sftp“, „none“) | | **externalOutputTarget.user** | String | Benutzername für das Zielsystem. | | **fileName** | String | Name der Datei, die beim Export erzeugt wird. | | **id** | Integer | Eindeutige ID des Datenfeeds. | | **lastExportFinished** | String | Zeitpunkt des Abschlusses des letzten erfolgreichen Exports (ISO 8601-Format, UTC). | | **lastExportStarted** | String | Zeitpunkt des Starts des letzten Exports (ISO 8601-Format, UTC). | | **name** | String | Name des Datenfeeds. | | **options.exportCharset** | String | Zeichensatz für die exportierte Datei (z. B. „utf-8“) | | **options.webhookTrigger** | String | Webhook, der nach Export ausgelöst wird (optional) | | **options.webhookTriggerOptions** | Object | Optionen für den Webhook-Trigger (optional) | | **options.webhookTriggerOptions.headers** | Object | HTTP-Header-Parameter als Schlüssel-Wert-Paare | | **options.webhookTriggerOptions.type** | String | Typ des Webhooks | | **options.zipType** | String | Kompressionstyp für Exportdatei (`"none"`, `"zip"`, `"gzip"`) | | **saveTarget** | String | Speicherziel des Exports:
    `“contentData”` – öffentlich abrufbar
    `“system”` – nicht öffentlich abrufbar | | **subshopIds** | Array | Liste der Subshops, für die der Datenfeed aktiv ist. | | **targetDirectory** | String | Zielverzeichnis, in dem die exportierte Datei gespeichert wird (überschreibt ggf. das Standardziel der Vorlage). | | **templateId** | Integer | ID der Vorlage, auf der der Datenfeed basiert. | | **templateName** | String | Name der Vorlage des Datenfeeds. Wird nur in der Listenansicht (GET datafeeds) zurückgegeben. | | **updatedAt** | String | Zeitpunkt der letzten Aktualisierung des Datenfeeds (ISO 8601-Format, UTC). | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "createdAt": "2025-03-24 16:34:58", "exportPlanOptions": { "exportAfterImport": true, "exportPlan": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 ] }, "exportStatus": "finished", "externalOutputTarget": { "host": "", "password": "", "port": 21, "remotePath": "", "type": "none", "user": "" }, "fileName": "test", "id": 226, "lastExportFinished": "2025-04-09 11:31:51", "lastExportStarted": "2025-04-09 11:31:46", "name": "test", "options": { "exportCharset": "utf-8", "webhookTrigger": "", "webhookTriggerOptions": { "headers": {}, "type": "" }, "zipType": "zip" }, "saveTarget": "contentData", "subshopIds": [ "deutsch" ], "targetDirectory": "/test", "templateId": 226, "updatedAt": "2025-03-25 11:21:56" } ``` ### Datenfeed-Vorlagen | **Name** | **Typ** | **Verwendung** | | ------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------- | | **id** | Integer | Eindeutige ID der Datenfeed-Vorlage | | **name** | String | Name der Datenfeed-Vorlage | | **content** | String | Der Inhalt der Vorlage. Hier darf die Template-Sprache verwendet werden. | | **createdAt** | String | Zeitpunkt der Erstellung | | **updatedAt** | String | Zeitpunkt der letzten Aktualisierung | | **usedBy** | Array | Liste der Namen von Datenfeeds, die diese Vorlage verwenden. Wird nur in der Listenansicht (GET datafeeds/templates) zurückgegeben. | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "content": "\n{{ \n var $product = true;\n while($product);\n $product = $wsProducts.loadNext() }}\n {{= $product.id }}\n {{= $product.name }}\n {{= $wsViews.url('Product', {productId: $product.id}, 'absolute') }}\n {{ /while }}\n", "createdAt": "2025-04-30 14:28:58", "id": 4, "name": "productsAsXML", "updatedAt": "2025-04-30 14:41:14" } ``` ## Methoden für Datenfeeds In diesem Abschnitt werden alle Endpunkte zur Verwaltung von Datenfeeds im Shopsystem beschrieben. Über die Schnittstelle können Datenfeeds erstellt, abgerufen, aktualisiert, gelöscht und geplant exportiert werden. ### GET datafeeds Diese Methode liefert eine paginierte Liste aller im System vorhandenen Datenfeeds.\ Standardmäßig werden 100 Einträge pro Anfrage zurückgegeben. Über den optionalen Parameter `size` kann die Anzahl der zurückgelieferten Datensätze angepasst werden – bis zu einem maximalen Wert von 300. Der `size`-Wert darf beliebig zwischen 1 und 300 gewählt werden.\ Die Ergebnisliste kann über definierte Filter- und Sortierparameter gezielt eingeschränkt und geordnet werden. Für den Zugriff ist eine Leseberechtigung für Datenfeeds erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/datafeeds ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "active": true, "createdAt": "2025-02-17 10:30:40", ... "templateName": "myTemplate", ... }, ... ], "nextPageToken": "MA", "totalCount": 1 } ``` #### Filterfelder `id`, `active`, `name`, `fileName`, `templateId`, `subshopIds`, `targetDirectory`, `exportStatus`, `lastExportStarted`, `lastExportFinished`, `createdAt`, `updatedAt` #### Sortierfelder `id`, `active`, `name`, `fileName`, `templateId`, `subshopIds`, `exportStatus`, `lastExportStarted`, `lastExportFinished`, `createdAt`, `updatedAt` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | --------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Datenfeeds. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET datafeeds/\{id} Diese Methode ruft die vollständigen Details eines einzelnen Datenfeeds anhand seiner eindeutigen ID ab. Der Endpunkt liefert alle konfigurierten Eigenschaften des Datenfeeds, einschließlich Name, Exportoptionen, Verzeichnisangaben und Statusinformationen. Der Zugriff erfordert die entsprechende Leseberechtigung für Datenfeeds. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/datafeeds/2 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "createdAt": "2025-02-17 10:30:40", "exportPlanOptions": { "exportAfterImport": false, "exportPlan": [] }, "exportStatus": "idle", "externalOutputTarget": { "host": "", "password": "", "port": 21, "remotePath": "", "type": "none", "user": "" }, "fileName": "foo", "id": 1, "lastExportFinished": "0000-00-00 00:00:00", "lastExportStarted": "0000-00-00 00:00:00", "name": "myDataFeed", "options": { "exportCharset": "utf-8", "webhookTrigger": "", "webhookTriggerOptions": { "headers": {}, "type": "" }, "zipType": "zip" }, "saveTarget": "system", "subshopIds": [ "deutsch", "english" ], "targetDirectory": "/bar", "templateId": 1, "updatedAt": "2025-02-17 10:30:40" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | --------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Datenfeeds. | | 400 Bad Request | "invalidValue" | `id` ist ungültig. | | 404 Not Found | | Datenfeed mit `id`=`{id}` wurde nicht gefunden. | ### PUT datafeeds/\{id} Diese Methode aktualisiert einen bestehenden Datenfeed anhand seiner eindeutigen ID. Daten bleiben bis zur Generierung unverändert. Im Request-Body können verschiedene Eigenschaften des Datenfeeds geändert werden, darunter Name, Status, Dateiname, Exportoptionen und Zielverzeichnisse. Die Felder`createdAt`, `updatedAt`, `lastExportStarted`, `lastExportFinished` und `exportStatus` können übergeben werden, werden jedoch vom System ignoriert und nicht überschrieben. Der aktualisierte Datenfeed wird als JSON-Objekt im Response zurückgegeben. Für die Ausführung sind Schreibberechtigungen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/datafeeds/1 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "newName", "active": true, "templateId": 1, "saveTarget": "system", "fileName": "foo", "targetDirectory": "/bar", "subshopIds": [ "deutsch", "english" ], "options": { "zipType": "zip" }, "exportPlanOptions": { "exportAfterImport": false, "exportPlan": [] }, "externalOutputTarget": { "type": "none", "host": "", "port": 21, "user": "", "password": "", "remotePath": "" } } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "createdAt": "2025-02-17 10:30:40", "exportPlanOptions": { "exportAfterImport": false, "exportPlan": [] }, "exportStatus": "finished", "externalOutputTarget": { "host": "", "password": "", "port": 21, "remotePath": "", "type": "none", "user": "" }, "fileName": "foo", "id": 1, "lastExportFinished": "2025-02-17 14:31:57", "lastExportStarted": "2025-02-17 14:31:52", "name": "newName", "options": { "exportCharset": "utf-8", "webhookTrigger": "", "webhookTriggerOptions": { "headers": {}, "type": "" }, "zipType": "zip" }, "saveTarget": "system", "subshopIds": [ "deutsch", "english" ], "targetDirectory": "/bar", "templateId": 1, "updatedAt": "2025-05-02 09:54:52" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Datenfeeds. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidCombination" | Wenn `active=true` gilt, kann `templateId` nicht 0 sein (Standard-Wert). | | 400 Bad Request | | | | 400 Bad Request | "invalidCharacters" | `fileName` enthält `/`, `\` oder `:`. | | 400 Bad Request | "invalidFormat" | `name`, `fileName`, `targetDirectory` oder `saveTarget` sind keine Strings
    `active` ist kein Boolean
    `templateId` ist keine Ganzzahl
    `subshopIds` ist kein Array von Strings
    `options` ist kein Objekt
    `options.zipType`, `options.exportCharset` oder `options.webhookTrigger` sind keine Strings
    `options.webhookTriggerOptions` ist kein Objekt
    `options.webhookTriggerOptions.type` ist kein String
    `options.webhookTriggerOptions.headerParams` ist kein Array
    Ein Element von `options.webhookTriggerOptions.headerParams` ist kein Objekt, oder `key` bzw. `value` darin ist kein String
    `externalOutputTarget` ist kein Objekt
    `externalOutputTarget.type`, `externalOutputTarget.host`, `externalOutputTarget.user`, `externalOutputTarget.password` oder `externalOutputTarget.remotePath` sind keine Strings
    `externalOutputTarget.port` ist keine Zahl
    `exportPlanOptions` ist kein Objekt
    `exportPlanOptions.exportAfterImport` ist kein Boolean
    `exportPlanOptions.exportPlan` ist kein Array. | | 400 Bad Request | "unknownDataField" | `options` enthält etwas außer `zipType`, `exportCharset`, `webhookTrigger` oder `webhookTriggerOptions`.
    `options.webhookTriggerOptions` enthält etwas außer `type` oder `headerParams`.
    Ein Element von `options.webhookTriggerOptions.headerParams` enthält etwas außer `key` oder `value`.
    `externalOutputTarget` enthält etwas außer `type`, `host`, `port`, `user`, `password` oder `remotePath`.
    `exportPlanOptions` enthält etwas außer `exportAfterImport` oder `exportPlan`.
    Request Body enthält ein unbekanntes Feld. | | 404 Not Found | | Datenfeed mit `id`=`{id}` wurde nicht gefunden. | | 409 Conflict | | Das Aktualisieren ist fehlgeschlagen.
    Der Dateipfad wird bereits verwendet. | ### POST datafeeds Diese Methode erstellt einen neuen Datenfeed. Die Eigenschaften des Datenfeeds, wie Name, Status, Dateiname, Exportoptionen und Zielverzeichnisse, werden über den Request-Body definiert. Die Felder `createdAt`, `updatedAt`, `lastExportStarted`, `lastExportFinished` und `exportStatus` können zwar übergeben werden, werden jedoch vom System ignoriert und automatisch gesetzt. Nach erfolgreicher Erstellung wird der vollständige Datenfeed als JSON-Objekt zurückgegeben. Die Ausführung setzt Erstellberechtigungen voraus. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/datafeeds ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "myFeed", "active": true, "templateId": 4, "saveTarget": "system", "fileName": "myFeed.csv", "targetDirectory": "/abc", "subshopIds": [ "deutsch", "english" ], "options": { "zipType": "zip" }, "exportPlanOptions": { "exportAfterImport": false, "exportPlan": [] }, "externalOutputTarget": { "type": "none", "host": "", "port": 21, "user": "", "password": "", "remotePath": "" } } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "createdAt": "2025-04-30 14:28:59", "exportPlanOptions": { "exportAfterImport": false, "exportPlan": [] }, "exportStatus": "idle", "externalOutputTarget": { "host": "", "password": "", "port": 21, "remotePath": "", "type": "none", "user": "" }, "fileName": "myFeed.csv", "id": 5, "lastExportFinished": "0000-00-00 00:00:00", "lastExportStarted": "0000-00-00 00:00:00", "name": "myFeed", "options": { "exportCharset": "utf-8", "webhookTrigger": "", "webhookTriggerOptions": { "headers": {}, "type": "" }, "zipType": "zip" }, "saveTarget": "system", "subshopIds": [ "deutsch", "english" ], "targetDirectory": "/abc", "templateId": 4, "updatedAt": "2025-04-30 14:28:59" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Datenfeeds. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "invalidCharacters" | `fileName` enthält `/`, `\` oder `:`. | | 400 Bad Request | "invalidFormat" | `name`, `fileName`, `targetDirectory` oder `saveTarget` sind keine Strings
    `active` ist kein Boolean
    `templateId` ist keine Ganzzahl
    `subshopIds` ist kein Array von Strings
    `options` ist kein Objekt
    `options.zipType`, `options.exportCharset` oder `options.webhookTrigger` sind keine Strings
    `options.webhookTriggerOptions` ist kein Objekt
    `options.webhookTriggerOptions.type` ist kein String
    `options.webhookTriggerOptions.headerParams` ist kein Array
    Ein Element von `options.webhookTriggerOptions.headerParams` ist kein Objekt, oder `key` bzw. `value` darin ist kein String
    `externalOutputTarget` ist kein Objekt
    `externalOutputTarget.type`, `externalOutputTarget.host`, `externalOutputTarget.user`, `externalOutputTarget.password` oder `externalOutputTarget.remotePath` sind keine Strings
    `externalOutputTarget.port` ist keine Zahl
    `exportPlanOptions` ist kein Objekt
    `exportPlanOptions.exportAfterImport` ist kein Boolean
    `exportPlanOptions.exportPlan` ist kein Array. | | 400 Bad Request | "unknownDataField" | `options` enthält etwas außer `zipType`, `exportCharset`, `webhookTrigger` oder `webhookTriggerOptions`.
    `options.webhookTriggerOptions` enthält etwas außer `type` oder `headerParams`.
    Ein Element von `options.webhookTriggerOptions.headerParams` enthält etwas außer `key` oder `value`.
    `externalOutputTarget` enthält etwas außer `type`, `host`, `port`, `user`, `password` oder `remotePath`.
    `exportPlanOptions` enthält etwas außer `exportAfterImport` oder `exportPlan`.
    Request Body enthält ein unbekanntes Feld. | | 409 Conflict | | Das Erstellen ist fehlgeschlagen. | ### DELETE datafeeds/\{id} Diese Methode löscht einen bestehenden Datenfeed dauerhaft anhand seiner eindeutigen ID. Der Zugriff auf diesen Endpunkt setzt Löschberechtigungen voraus. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/datafeeds/5 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {"success": true} ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ----------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Datenfeeds. | | 400 Bad Request | "invalidValue" | `id` ist ungültig. | | 404 Not Found | | Datenfeed mit `id`=`{id}` wurde nicht gefunden. | ## Methoden für Templates der Datenfeeds In diesem Abschnitt werden die Endpunkte zur Verwaltung von Templates für Datenfeeds beschrieben. Templates definieren die Struktur und die enthaltenen Felder eines Datenfeeds, wie Produktdaten, Kategoriedaten oder weitere Informationen. Vor der Erstellung eines Datenfeeds muss ein passendes Template angelegt werden, da dieses die Grundlage für den späteren Export bildet. ### GET datafeeds/templates Diese Methode liefert eine paginierte Liste aller im System vorhandenen Datenfeed-Templates. Über Filter- und Sortierparameter kann die Ergebnisliste eingeschränkt und sortiert werden. Die Templates bilden die Grundlage für die spätere Erstellung von Datenfeeds. Der Zugriff auf diesen Endpunkt erfordert Leseberechtigungen für Datenfeeds. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/datafeeds/templates ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "content": "tre", "createdAt": "2025-02-14 11:11:53", "id": 1, "name": "myTemplate", "updatedAt": "2025-02-14 11:11:53", "usedBy": [ "myDataFeed" ] }, ... ], "nextPageToken": "MA", "totalCount": 1 } ``` #### Filterfelder `id`, `name`, `content`, `createdAt`, `updatedAt` #### Sortierfelder `id`, `name`, `content`, `createdAt`, `updatedAt` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | ------------------------------------------------------------------------------- | | 401 Unauthorized | | Man ist kein Administrator und hat keine Berechtigung zum Lesen von Datenfeeds. | | 400 Bad Request | "invalidValue" | `size` ∉ \[1;300]
    `pageToken` ist keine Zahl oder kleiner als 0. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET datafeeds/templates/\{id} Diese Methode ruft die vollständigen Details einer einzelnen Datenfeed-Vorlage anhand ihrer eindeutigen ID ab. Die Antwort enthält die Stammdaten der Vorlage sowie deren inhaltliche Definition. Der Zugriff auf diesen Endpunkt setzt Leseberechtigungen für Datenfeeds voraus. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/datafeeds/templates/1234567 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "content": "something", "createdAt": "2025-02-14 11:11:53", "id": 1, "name": "myTemplate", "updatedAt": "2025-02-14 11:11:53" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | --------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Datenfeeds. | | 400 Bad Request | "invalidValue" | `id` ist ungültig. | | 404 Not Found | | Die Vorlage mit `id`=`{id}` wurde nicht gefunden. | ### PUT datafeeds/templates/\{id} Diese Methode aktualisiert eine bestehende Datenfeed-Vorlage anhand ihrer eindeutigen ID. Im Request-Body können der Name und der Inhalt (`content`) der Vorlage geändert werden. Die Felder `createdAt` und `updatedAt` können zwar übergeben werden, werden jedoch vom System automatisch verwaltet und nicht überschrieben. Nach erfolgreicher Aktualisierung wird die vollständige Vorlage im Response zurückgegeben. Schreibberechtigungen sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/datafeeds/templates/3 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "productsAsXML", "content": "\n{{ \n var $product = true;\n while($product);\n $product = $wsProducts.loadNext() }}\n {{= $product.id }}\n {{= $product.name }}\n {{= $wsViews.url('Product', {productId: $product.id}, 'absolute') }}\n {{ /while }}\n" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "content": "\n{{ \n var $product = true;\n while($product);\n $product = $wsProducts.loadNext() }}\n {{= $product.id }}\n {{= $product.name }}\n {{= $wsViews.url('Product', {productId: $product.id}, 'absolute') }}\n {{ /while }}\n", "createdAt": "2025-04-30 14:28:58", "id": 4, "name": "productsAsXML", "updatedAt": "2025-04-30 14:41:14" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Datenfeeds. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | `id` ist ungültig. `content` konnte nicht kompiliert werden. | | 400 Bad Request | "invalidFormat" | `name` oder `content` sind keine Strings | | 400 Bad Request | "unknownDataField" | Request Body enthält etwas außer `name`, `content`, `createdAt`, `updatedAt`. | | 409 Conflict | | Das Aktualisieren ist fehlgeschlagen. | | 404 Not found | | Die Vorlage wurde nicht gefunden. | ### POST datafeeds/templates Diese Methode erstellt eine neue Datenfeed-Vorlage im System. Im Request-Body müssen der Name der Vorlage sowie deren Inhalt (`content`) angegeben werden. Die Felder `createdAt` und `updatedAt` können übergeben werden, werden jedoch automatisch vom System gesetzt und nicht übernommen. Nach erfolgreicher Erstellung wird die vollständige Vorlage mit allen zugehörigen Informationen als JSON-Objekt zurückgegeben. Erstellberechtigungen sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/datafeeds/templates ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "myNewTemplate", "content": "id,name,url\n{{ var $product = true }}\n{{ while($product) }}\n{{ $product = $wsProducts.loadNext() }}\n{{= $product.id }}, {{= $product.name }}, {{= $wsViews.url('Product', {productId: $product.id}, 'absolute') }}\n{{ /while }}" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "content": "id,name,url\n{{ var $product = true }}\n{{ while($product) }}\n{{ $product = $wsProducts.loadNext() }}\n{{= $product.id }}, {{= $product.name }}, {{= $wsViews.url('Product', {productId: $product.id}, 'absolute') }}\n{{ /while }}", "createdAt": "2025-04-30 14:28:58", "id": 4, "name": "myNewTemplate", "updatedAt": "2025-04-30 14:28:58" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Datenfeeds. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidFormat" | `name` oder `content` sind keine Strings. | | 400 Bad Request | "missing" | `name` oder `content` fehlt. | | 400 Bad Request | "unknownDataField" | Request Body enthält etwas außer `name`, `content`, `createdAt`, `updatedAt`. | | 400 Bad Request | "invalidValue" | `name` oder `content` ist leer. `content` konnte nicht kompiliert werden. | | 409 Conflict | | Das Erstellen ist fehlgeschlagen. | ### POST datafeeds/templates/validate Diese Methode prüft, ob der übergebene Inhalt (`content`) einer Datenfeed-Vorlage syntaktisch korrekt ist. Dabei werden mögliche Formatierungsfehler oder Ungültigkeiten erkannt, bevor ein Template gespeichert oder verwendet wird. Der Request-Body muss das Feld `content` als String enthalten. Die Validierung speichert keine Daten, sondern dient ausschließlich der Überprüfung. Leseberechtigungen für Datenfeeds sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/datafeeds/templates/validate ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "content": "\n{{ \n var $product = true;\n while($product);\n $product = $wsProducts.loadNext() }}\n {{= $product.id }}\n {{= $product.name }}\n {{= $wsViews.url('Product', {productId: $product.id}, 'absolute') }}\n {{ /while }}\n" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "error": { "compilerErrors": [], "dependenciesError": false }, "valid": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | --------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Datenfeeds. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidFormat" | `content` ist kein String. | | 400 Bad Request | "missing" | `content` fehlt. | | 400 Bad Request | "unknownDataField" | Der Request Body enthält ein unbekanntes Feld. | ### DELETE datafeeds/templates/\{id} Diese Methode löscht eine bestehende Datenfeed-Vorlage anhand ihrer eindeutigen ID. Die erfolgreiche Löschung wird durch das JSON-Objekt `{"success": true}` und den Status-Code bestätigt. Eine Vorlage kann nur gelöscht werden, wenn sie nicht mehr in Verwendung ist. Für den Zugriff auf diesen Endpunkt sind Löschberechtigungen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/datafeeds/templates/4 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {"success": true} ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ----------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Datenfeeds. | | 400 Bad Request | "invalidValue" | `id` ist ungültig. | | 409 Conflict | | Die Vorlage wird noch verwendet. | | 404 Not Found | | Die Vorlage mit `id`=`{id}` wurde nicht gefunden. | ## Methoden zur Erstellung (Build) von Datenfeeds In diesem Abschnitt werden alle Endpunkte beschrieben, die den Build-Prozess von Datenfeeds steuern. Über die Schnittstelle können Build-Prozesse für einzelne oder alle Datenfeeds gestartet, der Status eines laufenden Builds abgefragt sowie zeit- oder importgesteuerte Builds vorbereitet werden. Die Build-Prozesse sorgen dafür, dass aktuelle und vollständige Exportdateien auf Basis der vorhandenen Templates und Daten erzeugt werden. ### GET datafeeds/build/\{id}/status Diese Methode liefert den aktuellen Status des Build-Prozesses eines Datenfeeds. Sie ermöglicht die Überwachung, ob ein Datenfeed derzeit erstellt wird, bereits abgeschlossen ist, oder, ob beim Erstellen Fehler aufgetreten sind. Jedes Element der Antwort enthält `filePath` (relativer Dateipfad) und `status` (Statusinformationen). Zusätzlich wird das Feld `url` zurückgegeben, wenn `saveTarget` des Datenfeeds `"contentData"` ist. Für den Zugriff sind Leseberechtigungen für Datenfeeds erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/datafeeds/build/2/status ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "filePath": "/abc/deutsch_myFeed.csv.zip", "status": { "createdAt": "2025-04-30 14:28:59", "datafeedId": 5, "exportStatus": "finished", "id": 1, "lastExportError": "", "lastExportFinished": "2025-04-30 14:29:00", "lastExportStarted": "2025-04-30 14:28:59", "subshopId": "deutsch", "updatedAt": "2025-04-30 14:29:00" } }, { "filePath": "/abc/english_myFeed.csv.zip", "status": { "createdAt": "2025-04-30 14:28:59", "datafeedId": 5, "exportStatus": "finished", "id": 2, "lastExportError": "", "lastExportFinished": "2025-04-30 14:28:59", "lastExportStarted": "2025-04-30 14:28:59", "subshopId": "english", "updatedAt": "2025-04-30 14:28:59" } } ] ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | --------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Datenfeeds. | | 400 Bad Request | "invalidValue" | `id` ist ungültig. | | 404 Not Found | | Datenfeed mit `id`=`{id}` wurde nicht gefunden. | | 400 Bad Request | | Die korrespondierende Vorlage konnte nicht gefunden werden. | ### POST datafeeds/build/all Diese Methode startet den Build-Prozess für alle im System vorhandenen Datenfeeds. Dabei werden sämtliche definierten Datenfeeds neu erstellt. Die Ausführung erfolgt asynchron; der Endpunkt bestätigt lediglich das Starten des Prozesses. Freigabeberechtigungen für Datenfeeds sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/datafeeds/build/all ``` #### Request Body ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {"success": true} ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------- | ------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Veröffentlichen von Datenfeeds. | | 503 Service Unavailable | "serviceUnavailable" | `FeedBuilderUrl` existiert nicht, oder das Generieren ist fehlgeschlagen. | ### POST datafeeds/build/\{id} Diese Methode startet den Build-Prozess für einen bestimmten Datenfeed anhand seiner eindeutigen ID. Dabei wird der ausgewählte Feed neu erstellt. Die Ausführung erfolgt asynchron; der Endpunkt bestätigt lediglich das Starten des Build-Prozesses. Mit dem optionalen Query-Parameter `subshopId` (kann mehrfach angegeben werden) kann der Build auf bestimmte Subshops eingeschränkt werden. Freigabeberechtigungen für Datenfeeds sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/datafeeds/build/2 ``` #### Request Body ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {"success": true} ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------- | ------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Veröffentlichen von Datenfeeds. | | 400 Bad Request | "invalidValue" | `id` ist ungültig. | | 404 Not Found | | Datenfeed mit `id`=`{id}` wurde nicht gefunden. | | 503 Service Unavailable | "serviceUnavailable" | `FeedBuilderUrl` existiert nicht, oder das Generieren ist fehlgeschlagen. | ### POST datafeeds/build/hour/\{hour} Diese Methode startet die Generierung von Datenfeeds, die zu einer bestimmten Stunde generiert werden müssen. Der Pfadparameter `{hour}` bestimmt die Stunde im 24-Stunden-Format (`0` bis `23`). Die Generierung erfolgt asynchron – das bedeutet, dass die Antwort keine fertige Datei zurückliefert, sondern lediglich den Start des Prozesses bestätigt. Freigabeberechtigungen für Datenfeeds sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/datafeeds/build/hour/12 ``` #### Request Body ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {"success": true} ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------- | ------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Veröffentlichen von Datenfeeds. | | 404 Not Found | | Der Parameter `hour` fehlt oder ist ungültig. | | 503 Service Unavailable | "serviceUnavailable" | `FeedBuilderUrl` existiert nicht, oder die Generierung ist fehlgeschlagen. | ### POST datafeeds/build/import Diese Methode startet den Build-Prozess für alle Datenfeeds, die nach einem Importvorgang automatisch generiert werden sollen. Die Erstellung der Feeds erfolgt asynchron. Freigabeberechtigungen für Datenfeeds sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/datafeeds/build/import ``` #### Request Body ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {"success": true} ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------- | ------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Veröffentlichen von Datenfeeds. | | 503 Service Unavailable | "serviceUnavailable" | `FeedBuilderUrl` existiert nicht, oder die Generierung ist fehlgeschlagen. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Gutscheine Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-gutscheine Gutscheine, Chargen, Blaupausen und Vorlagen über die Admin Interface API anlegen, abrufen und löschen sowie Bulk-Aktionen ausführen. Der Endpunkt `vouchers/` stellt Ihnen eine Schnittstelle zur Verfügung mit der Sie Gutscheine in unserem Shop-System verwalten können. Mit dieser Schnittstelle können Sie Gutscheine erzeugen, löschen, Vorlagen erstellen und und vorhandene Gutscheine einsehen. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | ------------------------ | ------------------- | --------------------- | --------------------- | --------------------- | --------------------- | | **Gutscheine** | vouchers/ | | | | | | **Gutscheine (Bulk)** | vouchers/bulk | | | | | | **Gutschein-Chargen** | vouchers/charges/ | | | | | | **Gutschein-Blaupausen** | vouchers/templates/ | | | | | | **Gutschein-Vorlagen** | vouchers/presets/ | | | | | ## Datenfelder ### Datenfelder eines Gutscheins | Name | Typ | Bedeutung | | --------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------ | | active | Boolean | Gibt an, ob der Gutschein aktiv ist (true = aktiv, false = deaktiviert). | | chargeId | String | ID der Charge, zu der der Gutschein gehört. | | createdAt | String | Zeitpunkt der Erstellung des Gutscheins. | | id | String | Eindeutige ID des Gutscheins. | | labels | String\[] | Tags oder Bezeichnungen zur Gruppierung oder Identifikation des Gutscheins (z. B. Marketingaktionen). | | maxUseCount | Integer | Maximale Anzahl an Einlösungen, bevor der Gutschein deaktiviert wird. | | pool | Boolean | Gibt an, ob der Gutschein Teil eines Pools ist (gemeinsamer Kontingent). | | types.appOnly | Boolean | Gutschein kann nur über die App eingelöst werden. | | types.discount | Boolean | Werbegutschein / Kaufgutschein | | types.freeShipping | Boolean | Gutschein gewährt kostenlosen Versand. | | types.keepSurplus | Boolean | Verbleibender Restwert darf behalten und später erneut eingelöst werden. | | types.multipleCustomer | Boolean | Gutschein ist mehrfach von verschiedenen Kunden einlösbar. | | types.newCustomersOnly | Boolean | Gutschein darf nur von Neukunden verwendet werden. | | types.existingCustomersOnly | Boolean | Gutschein darf nur von Bestandskunden verwendet werden. Kann nicht zusammen mit `types.newCustomersOnly` gesetzt werden. | | types.maxUseCountSet | Boolean | Gutschein ist pro Benutzer begrenzt einlösbar. | | types.maxUseCountPerUser | Integer | Maximale Anzahl an Einlösungen pro Benutzer | | updatedAt | String | Zeitpunkt der letzten Aktualisierung des Gutscheins. | | validCustomers\[].id | Integer | ID eines Kunden, der berechtigt ist, den Gutschein einzulösen. | | validCustomers\[].number | String | Kundennummer eines berechtigten Kunden. | | validProducts\[].number | String | Produktnummer, für das der Gutschein gültig ist. | | validProducts\[].quantity | Integer | Mindestanzahl des Produkts im Warenkorb, damit Gutschein gilt. | | validSubshops\[] | String\[] | Liste der Subshop-IDs, in denen der Gutschein gültig ist. | | values\[].currency | String | Währungscode (z. B. EUR, GBP), für den der jeweilige Wert gilt. | | values\[].percentValue | Float | Prozentualer Rabatt (z. B. 0.1 für 10 %). | | values\[].taxId | String | Steuer-ID, die auf den Gutscheinwert angewendet wird. | | values\[].usedValue | Float | Bereits eingelöster Wert des Gutscheins (für Mehrfachnutzung). | | values\[].value | Float | Gesamtwert des Gutscheins in der jeweiligen Währung. | | values\[].minOrderValue | Float | Mindestbestellwert in der Währung, um den Gutschein einzulösen. | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "chargeId": "example-charge", "createdAt": "2025-01-17T07:57:26.000Z", "id": "VOUCHER-XY57Z3", "labels": [ "summer2025" ], "maxUseCount": 5, "pool": false, "types": { "appOnly": false, "discount": false, "freeShipping": false, "keepSurplus": true, "multipleCustomer": false, "newCustomersOnly": false, "maxUseCountPerUser": 122, "maxUseCountSet": true }, "updatedAt": "2025-01-17T07:57:26.000Z", "validCustomers": [ { "id": 48 }, { "number": "1234" } ], "validProducts": [ { "number": "go1", "quantity": 1 } ], "validSubshops": [ "deutsch" ], "values": [ { "currency": "EUR", "percentValue": 0.0, "taxId": "", "usedValue": 10.0, "value": 42.0 }, { "currency": "GBP", "minOrderValue": 50.0, "percentValue": 0.0, "taxId": "", "value": 10.0 } ] } ``` ### Datenfelder einer Gutschein-Charge | **Name** | **Typ** | **Bedeutung** | | ---------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **createdAt** | String | Zeitpunkt der Erstellung der Gutscheinladung (ISO 8601-Format, UTC). | | **creator** | Integer | ID des Benutzers, der die Charge erstellt hat. | | **description** | String | Freitextbeschreibung der Gutschein-Charge. | | **id** | String | Eindeutige ID der Gutschein-Charge. | | **name** | String | Name der Gutschein-Charge. | | **redeemed** | Integer | Gibt an, ob Gutscheine der Charge eingelöst wurden.
    Mögliche Werte:
    `0 = NotRedeemed`
    `1 = PartiallyRedeemed`
    `2 = Redeemed` | | **updatedAt** | String | Zeitpunkt der letzten Aktualisierung der Charge (ISO 8601-Format, UTC). | | **voucherChargeCount** | Integer | Anzahl der mit dieser Charge erstellten Gutscheine. | | **voucherData** | Objekt | Details zu Gutscheinen. Alle Felder stimmen mit [den Feldern der Gutscheine](https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3058532517/API-Referenz+Gutscheine#21-datenfelder-eines-gutscheins) überein. | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-04-11T13:25:53.000Z", "creator": 1, "description": "", "id": "82", "name": "myCharge", "redeemed": 0, "updatedAt": "2025-04-11T13:25:53.000Z", "voucherChargeCount": 1, "voucherData": { "labels": [ "82" ], "maxUseCount": 999, "pool": false, "types": { "appOnly": false, "discount": true, "freeShipping": true, "keepSurplus": false, "maxUseCountSet": false, "multipleCustomer": true, "newCustomersOnly": false }, "validProducts": [ { "id": "100-41232", "quantity": 1 } ], "values": [ { "currency": "EUR", "minOrderValue": 1, "percentValue": 0, "taxId": "19", "usedValue": 0, "value": 55 } ] } } ``` ### Datenfelder einer Gutschein-Blaupause | **Name** | **Typ** | **Bedeutung** | | ------------------------- | ------- | -------------------------------------------------------------------------- | | **active (optional)** | Boolean | Gibt an, ob die Blaupause aktiv ist. | | **createdAt** | String | Zeitpunkt, zu dem die Blaupause erstellt wurde (ISO 8601-Format, UTC). | | **templateId** | String | Technische ID oder eindeutiger Name der Gutscheinblaupause. | | **updatedAt** | String | Zeitpunkt der letzten Aktualisierung der Blaupause (ISO 8601-Format, UTC). | | **validFrom (optional)** | String | Beginn der Gültigkeit. | | **validUntil (optional)** | String | Ende der Gültigkeit. | Weitere Felder stimmen mit [den Feldern der Gutscheine](/schnittstellen/admin-interface-api/api-referenz-gutscheine) überein. #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "chargeId": "53", "createdAt": "2025-04-09T08:57:59.000Z", "labels": [], "templateId": "newTemplateName2", "types": { "appOnly": false, "discount": false, "freeShipping": false, "keepSurplus": false, "maxUseCountSet": false, "multipleCustomer": false, "newCustomersOnly": false }, "updatedAt": "2025-04-29T08:48:39.000Z", "values": [ { "currency": "EUR", "minOrderValue": 10, "percentValue": 0, "taxId": "", "value": 1 } ] } ``` ### Datenfelder einer Gutschein-Vorlage | **Name** | **Typ** | **Bedeutung** | | -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | **createdAt** | String | Zeitpunkt, zu dem die Vorlage erstellt wurde (ISO 8601-Format, UTC). | | **updatedAt** | String | Zeitpunkt der letzten Aktualisierung der Vorlage (ISO 8601-Format, UTC). | | **presetId** | String | Technische ID oder eindeutiger Name der Gutscheinvorlage. | | **system** | Boolean | Gibt an, ob die Vorlage von Websale bereitgestellt wurde. Bei solchen Vorlagen können nicht alle Felder bearbeitet werden. | | **data.count** | Integer | Anzahl der Gutscheine | | **data.data** | Objekt | Details zum Gutschein. Alle Felder stimmen mit [den Feldern der Gutscheine](/schnittstellen/admin-interface-api/api-referenz-gutscheine) überein. | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "1970-01-01T00:33:45.000Z", "data": { "count": 1, "data": { "active": true, "basketProducts": [], "chargeId": "", "labels": [], "maxUseCount": 19, "name": "myPreset", "types": { "appOnly": false, "discount": true, "freeShipping": false, "keepSurplus": false, "maxUseCountSet": false, "multipleCustomer": true }, "values": [ { "currency": "GBP", "minOrderValue": 40, "taxId": "19", "value": 20 } ] } }, "presetId": "myPreset", "system": false, "updatedAt": "1970-01-01T00:33:45.000Z" } ``` ## Methoden zur Verwaltung von Gutscheinen In diesem Abschnitt werden alle Endpunkte zur Verwaltung einzelner Gutscheine beschrieben. Über die Schnittstelle können Gutscheine erstellt, aktualisiert, gelöscht und abgerufen werden. Die Verwaltung von Gutschein-Chargen wird in einem eigenen Abschnitt separat behandelt. Für alle Operationen sind entsprechende Lese-, Schreib-, Erstell- oder Löschberechtigungen erforderlich. ### GET vouchers Diese Methode liefert eine paginierte Liste aller im System vorhandenen Gutscheine. Über Filter- und Sortierparameter können die Ergebnisse gezielt eingeschränkt und geordnet werden. Die zurückgegebenen Gutscheindaten umfassen Informationen zu Aktivität, Gültigkeit, Einlösebedingungen und Wertangaben. Für den Zugriff sind Leseberechtigungen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers?size=100 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "active": true, "chargeId": "example-charge", "createdAt": "2025-01-17T07:57:26.000Z", "id": "VOUCHER-XY57Z3", "labels": [ "summer2025" ], "maxUseCount": 5, "pool": false, "types": { "appOnly": false, "discount": false, "freeShipping": false, "keepSurplus": true, "multipleCustomer": false, "newCustomersOnly": false, "maxUseCountSet": false }, "updatedAt": "2025-01-17T07:57:26.000Z", "validCustomers": [ { "id": 48 }, { "number": "1234" } ], "validProducts": [ { "number": "go1", "quantity": 1 } ], "validSubshops": [ "deutsch" ], "values": [ { "currency": "EUR", "percentValue": 0.0, "taxId": "", "usedValue": 10.0, "value": 42.0 }, { "currency": "GBP", "minOrderValue": 50.0, "percentValue": 0.0, "taxId": "", "value": 10.0 } ] } ], "nextPageToken": "Mw", "totalCount": 1 } ``` #### Filterfelder `id`, `active`, `pool`, `chargeId`, `createdAt`, `updatedAt`, `validFrom`, `validUntil`, `maxUseCount` #### Sortierfelder `id`, `active`, `pool`, `chargeId`, `createdAt`, `updatedAt`, `validFrom`, `validUntil`, `maxUseCount` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Gutschein-Daten. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### PUT vouchers/\{id} - Coming soon Diese Methode aktualisiert die Eigenschaften eines bestehenden Gutscheins anhand seiner eindeutigen ID. Über den Request-Body können verschiedene Felder wie Aktivierungsstatus, Gültigkeitszeiträume, Werte oder Einlösebedingungen geändert werden. Nach erfolgreicher Aktualisierung wird eine Bestätigung zurückgegeben. Schreibberechtigungen für Gutschein-Daten sind erforderlich. Diese Methode ist derzeit noch nicht implementiert und für eine zukünftige Version geplant. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/1CUA-8341-FD8Q-KPJ2 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "updateVoucher": "not implemented" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Gutschein-Daten. | ### POST vouchers Diese Methode erstellt einen oder mehrere neue Gutscheine. Die Gutscheine können entweder einer neuen Charge zugeordnet oder an eine bestehende Charge angehängt werden. Damit eine neue Charge erstellt wird, muss das Feld `chargeId` im Request Body leer sein. Pro Anfrage können maximal 10.000 Gutscheine erstellt werden. Nach erfolgreicher Erstellung werden die zugehörige Charge-ID sowie die Anzahl der erzeugten Gutscheine zurückgegeben. Erstellberechtigungen für Gutschein-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "count": 1, "data": { "active": true, "name": "cvcv89", "chargeId": "", "maxUseCount": 1, "values": [ { "value": 55, "currency": "GBP", "minOrderValue": 55, "taxId": "" } ], "types": { "keepSurplus": false, "discount": true, "freeShipping": false, "maxUseCountPerUser": 1, "maxUseCountSet": true, "multipleCustomer": true, "appOnly": false }, "basketProducts": [], "labels": [] } } ``` #### Antwort ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true, "chargeId": "122", "count": 1 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Gutschein-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidFormat" | `count` ist keine Zahl.
    `data` ist kein Objekt. | | 400 Bad Request | "missing" | `data` fehlt.
    `appendToCharge` ist `true`, und `chargeId` fehlt. | | 400 Bad Request | "invalidValue" | `count` ∉ \[1;10000] | | 400 Bad Request | "invalidCombination" | `count` ≠ 1 und `voucherId` ist nicht leer. Beim Erstellen von mehreren Gutscheinen wird die Id automatisch generiert und kann nicht manuell gesetzt werden.
    `newCustomersOnly` und `existingCustomersOnly` sind gesetzt. | | 400 Bad Request | "duplicateEntry" | `voucherId` oder `chargeId` existieren bereits. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body übergeben. | ### DELETE vouchers/\{id} Diese Methode löscht einen bestehenden Gutschein anhand seiner eindeutigen ID. Nach erfolgreicher Löschung wird die ID des entfernten Gutscheins als Bestätigung zurückgegeben. Für die Ausführung sind Löschberechtigungen für Gutschein-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/ZZ3R-2ZPC-UDGF-S6DG ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "ZZ3R-2ZPC-UDGF-S6DG" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ---------- | ---------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Gutschein-Daten. | | 400 Bad Request | "notFound" | Der Gutschein wurde nicht gefunden. | ### POST vouchers/bulk Diese Methode ermöglicht das Erstellen oder Aktualisieren mehrerer Gutscheine in einem einzigen Request (Massenimport). Der Request Body muss ein JSON-Array enthalten, in dem jedes Element ein Objekt mit einem `data`-Feld ist, das die Gutscheindaten enthält. Pro Anfrage können maximal 10.000 Einträge übergeben werden. Ungültige Einträge werden übersprungen und in der Antwort unter `skippedLines` aufgeführt. Falls ein Gutschein mit derselben ID bereits existiert, wird geprüft, ob die Daten kompatibel sind. Mit dem Query-Parameter `?force` kann ein Update erzwungen werden. Erstellberechtigungen für Gutschein-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/bulk ``` #### Query-Parameter | **Parameter** | **Typ** | **Bedeutung** | | ------------- | ------- | ----------------------------------------------------------------------------------------------------- | | force | Flag | Wenn gesetzt, werden bestehende Gutscheine mit derselben ID ohne Kompatibilitätsprüfung aktualisiert. | #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "data": { "id": "BULK-0001", "active": true, "chargeId": "charge-1", "maxUseCount": 1, "values": [ { "value": 10, "currency": "EUR", "minOrderValue": 20, "taxId": "" } ], "types": { "keepSurplus": false, "discount": true, "freeShipping": false, "maxUseCountPerUser": 1, "maxUseCountSet": true, "multipleCustomer": false, "appOnly": false }, "basketProducts": [], "labels": ["import-2025"] } }, { "data": { "id": "BULK-0002", "active": true, "chargeId": "charge-1", "maxUseCount": 5, "values": [ { "value": 25, "currency": "EUR", "minOrderValue": 50, "taxId": "" } ], "types": { "keepSurplus": true, "discount": false, "freeShipping": false, "maxUseCountPerUser": 1, "maxUseCountSet": false, "multipleCustomer": true, "appOnly": false }, "basketProducts": [], "labels": [] } } ] ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ "BULK-0001", "BULK-0002" ], "skippedLines": [] } ``` #### Antwort mit übersprungenen Zeilen ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ "BULK-0001" ], "skippedLines": [ { "lineNumber": 2, "errorType": "invalidParameters", "fieldErrors": { "data": "invalidFormat" } } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------------- | ------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Gutschein-Daten. | | 400 Bad Request | | Request Body konnte nicht geladen werden oder ist kein Array. | | 400 Bad Request | "invalidFormat" | Ein Element im Array enthält kein gültiges `data`-Objekt. | | 400 Bad Request | "invalidValue" | Die Charge-ID (`chargeId`) existiert bereits mit einem anderen Typ. | | 400 Bad Request | "invalidCombination" | `newCustomersOnly` und `existingCustomersOnly` sind gleichzeitig gesetzt. | ### DELETE vouchers/bulk Diese Methode ermöglicht das Löschen mehrerer Gutscheine in einem einzigen Request. Der Request Body muss ein JSON-Array enthalten, in dem jedes Element ein Objekt mit der `id` des zu löschenden Gutscheins ist. Pro Anfrage können maximal 10.000 Einträge übergeben werden. Ungültige Einträge werden übersprungen und in der Antwort unter `skippedItems` aufgeführt. Löschberechtigungen für Gutschein-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/bulk ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "id": "BULK-0001" }, { "id": "BULK-0002", "pool": true } ] ``` #### Datenfelder pro Eintrag | **Feld** | **Typ** | **Pflicht** | **Bedeutung** | | -------- | ------- | ----------- | ------------------------------------------------------------------------ | | id | String | Ja | Die eindeutige ID des zu löschenden Gutscheins. | | pool | Boolean | Nein | Gibt an, ob es sich um einen Pool-Gutschein handelt (Standard: `false`). | #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ "BULK-0001", "BULK-0002" ], "skippedItems": [] } ``` #### Antwort mit übersprungenen Einträgen ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ "BULK-0001" ], "skippedItems": [ { "lineNumber": 2, "errorType": "invalidParameters", "fieldErrors": { "id": "missing" } } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | --------------- | ---------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Gutschein-Daten. | | 400 Bad Request | | Request Body konnte nicht geladen werden oder ist kein Array. | | 400 Bad Request | "invalidFormat" | Ein Element im Array ist kein gültiges JSON-Objekt. | | 400 Bad Request | "missing" | Das Pflichtfeld `id` fehlt in einem Eintrag. | ## Methoden für Gutschein-Chargen In diesem Abschnitt werden alle Endpunkte zur Verwaltung von Gutschein-Chargen beschrieben. Eine Gutschein-Charge ist eine Gruppe von Gutscheinen, die gemeinsam erstellt und verwaltet werden können. Über die Schnittstelle können Chargen aufgelistet, gefiltert, erstellt, aktualisiert, exportiert und gelöscht werden. Zudem können Ersteller-Informationen und Labels von bestehenden Chargen abgerufen werden. Für alle Operationen sind entsprechende Lese-, Schreib-, Erstell- oder Löschberechtigungen erforderlich. ### GET vouchers/charges Diese Methode liefert eine paginierte Liste aller im System vorhandenen Gutschein-Chargen. Über Filter- und Sortierparameter kann die Liste nach verschiedenen Kriterien eingeschränkt und geordnet werden. Die zurückgegebenen Daten enthalten Informationen zur Charge selbst sowie zu den zugehörigen Gutschein-Einstellungen. Für den Zugriff sind Leseberechtigungen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/charges?size=100 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "createdAt": "2025-01-17T07:56:50.000Z", "creator": 0, "description": "Example Charge", "id": "example-charge", "name": "Example Charge", "redeemed": 0, "updatedAt": "2025-01-17T07:56:50.000Z", "voucherChargeCount": 1, "voucherData": { "labels": [ "bar" ], "maxUseCount": 5, "pool": false, "types": { "appOnly": false, "discount": false, "freeShipping": false, "keepSurplus": true, "multipleCustomer": false, "newCustomersOnly": false, "maxUseCountSet": false }, "validCustomers": [ { "id": 48 }, { "number": "1234" } ], "validProducts": [ { "number": "go1", "quantity": 1 } ], "validSubshops": [ "deutsch" ], "values": [ { "currency": "EUR", "percentValue": 0.0, "taxId": "", "usedValue": 10.0, "value": 42.0 }, { "currency": "GBP", "minOrderValue": 50.0, "percentValue": 0.0, "taxId": "", "value": 10.0 } ] } } ], "nextPageToken": "MQ", "totalCount": 1 } ``` #### Filterfelder `id`, `createdAt`, `updatedAt`, `type`, `name`, `creator`, `labels`, `description` #### Sortierfelder `id`, `createdAt`, `updatedAt`, `type`, `name`, `creator`, `description` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Gutschein-Daten. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET vouchers/charges/creators Diese Methode liefert eine Liste der Benutzerkonten mit Ids und E-Mails, die Gutschein-Chargen erstellt haben. Bei manuell angelegten Chargen entspricht der Name der E-Mail-Adresse des Benutzerkontos, bei importierten Chargen wird stattdessen "Import" angezeigt. Für den Zugriff sind Leseberechtigungen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/charges/creators ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "id": 42, "name": "m.mustermann@websale.de" } ] ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Gutschein-Daten. | ### GET vouchers/charges/labels Diese Methode liefert eine Liste aller vergebenen Labels für Gutschein-Chargen. Labels dienen der Kategorisierung von Chargen und werden bei der Volltextsuche berücksichtigt. Der Zugriff auf diese Informationen setzt Leseberechtigungen für Gutschein-Daten voraus. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/charges/labels ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ "label1", "label2" ] ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Gutschein-Daten. | ### PUT vouchers/charges/\{chargeid} - Coming soon Diese Methode aktualisiert die Eigenschaften einer bestehenden Gutschein-Charge anhand ihrer eindeutigen ID. Über den Request-Body können Felder wie Name, Beschreibung oder zusätzliche Labels geändert werden. Nach erfolgreicher Aktualisierung wird eine Bestätigung zurückgegeben. Schreibberechtigungen für Gutschein-Daten sind erforderlich. Diese Methode ist derzeit noch nicht implementiert und für eine zukünftige Version geplant. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/charges/123456789 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "updateCharge": "not implemented" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Gutschein-Daten. | ### DELETE vouchers/charges/\{chargeid} Diese Methode löscht eine bestehende Gutschein-Charge samt aller darin enthaltenen Gutscheine anhand der angegebenen Charge-ID. Nach erfolgreicher Löschung wird die ID der entfernten Charge als Bestätigung zurückgegeben. Für die Ausführung sind Löschberechtigungen für Gutschein-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/charges/123456789 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "chargeId": "123456789" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ---------- | ---------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Gutschein-Daten. | | 400 Bad Request | "notFound" | Die Charge wurde nicht gefunden. | ## Methoden für Gutschein-Blaupausen In diesem Abschnitt werden alle Endpunkte zur Verwaltung von Gutschein-Blaupausen (Templates) beschrieben. Gutschein-Blaupausen definieren vordefinierte Konfigurationen wie Rabatttypen, Gültigkeitszeiträume, Werte und weitere Bedingungen für Gutscheine. Über die Schnittstelle können Blaupausen erstellt, aktualisiert, abgerufen, gelöscht und mit Labels organisiert werden. **Hinweis:** Das Feld `templateId` entspricht intern der Spalte `name` in der Datenbank. Trotz dieser Zuordnung darf im Rahmen der API jedoch nicht nach `name` sortiert, gefiltert oder der Wert explizit abgefragt oder gesetzt werden. Alle Vorgänge erfolgen ausschließlich über `templateId`. Für alle Operationen sind entsprechende Lese-, Schreib-, Erstell- oder Löschberechtigungen erforderlich. ### GET vouchers/templates Diese Methode liefert eine paginierte Liste aller vorhandenen Gutschein-Blaupausen (Templates). Über Filter- und Sortierparameter kann die Liste eingeschränkt und geordnet werden. Die Blaupausen definieren Standardwerte für Gutscheine oder Gutschein-Chargen, die später auf Basis dieser Blaupausen erstellt werden können. Für den Zugriff sind Leseberechtigungen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/templates ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "active": true, "chargeId": "template-charge", "createdAt": "2025-02-19T12:45:47.000Z", "labels": [], "templateId": "Example Template", "types": { "appOnly": false, "discount": false, "freeShipping": false, "keepSurplus": false, "multipleCustomer": false, "newCustomersOnly": false, "maxUseCountSet": false }, "updatedAt": "2025-02-19T12:45:47.000Z", "values": [ { "currency": "EUR", "minOrderValue": 0.0, "percentValue": 0.0, "taxId": "", "value": 1.0 } ] } ], "nextPageToken": "MA", "totalCount": 1 } ``` #### Filterfelder `templateId`, `chargeId`, `labels`, `value`, `active`, `createdAt`, `updatedAt`, `validFrom`, `validUntil`, `maxUseCount` #### Sortierfelder `id`, `templateId`, `chargeId`, `createdAt`, `updatedAt`, `active`, `validFrom`, `validUntil`, `maxUseCount` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Gutschein-Daten. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET vouchers/templates/labels Diese Methode liefert eine Liste aller vergebenen Labels, die bei Gutschein-Blaupausen (Templates) verwendet wurden. Labels dienen der Kategorisierung von Blaupausen und werden bei der Volltextsuche berücksichtigt. Für den Zugriff sind Leseberechtigungen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/templates/labels ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ "label1", "label2" ] ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Gutschein-Daten. | ### PUT vouchers/templates/\{templateId} Diese Methode aktualisiert die Eigenschaften einer bestehenden Gutschein-Blaupausen (Template) anhand ihrer eindeutigen ID, wobei die ID dem Namen der Blaupause entspricht. Über den Request-Body können Felder wie Name, Status, Werte, Typen oder Labels angepasst werden. Nach erfolgreicher Aktualisierung wird die `templateId` der bearbeitete Blaupause zurückgegeben. Schreibberechtigungen für Gutschein-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/templates/oldTemplateName ``` #### Anfrage ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "templateId": "newTemplateName", "data": { "active": true, "chargeId": "54", "createdAt": "2025-02-19T12:45:47.000Z", "labels": [], "types": { "appOnly": false, "discount": false, "freeShipping": false, "keepSurplus": false, "multipleCustomer": false, "newCustomersOnly": false, "maxUseCountSet": false }, "updatedAt": "2025-02-19T12:45:47.000Z", "values": [ { "currency": "EUR", "minOrderValue": 0.0, "percentValue": 0.0, "taxId": "", "value": 1.0 } ] } } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "chargeId": "54", "createdAt": "2025-02-19T12:45:47.000Z", "labels": [], "templateId": "newTemplateName", "types": { "appOnly": false, "discount": false, "freeShipping": false, "keepSurplus": false, "multipleCustomer": false, "newCustomersOnly": false, "maxUseCountSet": false }, "updatedAt": "2025-02-19T12:45:47.000Z", "values": [ { "currency": "EUR", "minOrderValue": 0.0, "percentValue": 0.0, "taxId": "", "value": 1.0 } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Gutschein-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidFormat" | `templateId` ist kein String.
    `data` ist kein Objekt. | | 400 Bad Request | "missing" | `templateId` oder `data` fehlt. | | 400 Bad Request | "invalidValue" | `chargeId` verweist auf eine nicht existierende Charge. | | 400 Bad Request | "duplicateEntry" | `name` oder `chargeId` wurden schon verwendet. | | 400 Bad Request | "notFound" | Die Blaupause wurde nicht gefunden. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body übergeben. | ### POST vouchers/templates Diese Methode erstellt eine neue Gutschein-Blaupause (Template) anhand der übermittelten Konfigurationsdaten. Der Request-Body muss eine eindeutige `templateId` sowie ein `data`-Objekt mit den relevanten Gutscheineinstellungen enthalten. Nach erfolgreicher Erstellung wird die ID der neuen Blaupause zurückgegeben. Erstellberechtigungen für Gutschein-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/templates ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "templateId": "myNewTemplate", "data": { "data": { "active": true, "name": "myNewTemplate", "chargeId": "", "maxUseCount": 1, "values": [ { "value": 15, "currency": "EUR", "minOrderValue": 55, "taxId": "19" } ], "types": { "keepSurplus": false, "discount": true, "freeShipping": false, "maxUseCountSet": false, "multipleCustomer": true, "appOnly": false }, "basketProducts": [ { "id": "100-41232" } ], "labels": [ "Summer" ] }, "templateId": "myNewTemplate" } } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": null, "chargeId": "55", "createdAt": "2025-02-19T12:45:47.000Z", "labels": [ "Summer" ], "templateId": "myNewTemplate", "types": { "appOnly": false, "discount": true, "freeShipping": false, "keepSurplus": false, "maxUseCountSet": false, "multipleCustomer": true, "newCustomersOnly": false }, "updatedAt": "2025-02-19T12:45:47.000Z", "values": [ { "currency": "EUR", "minOrderValue": 55, "percentValue": 0, "taxId": "19", "value": 15 } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Gutschein-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidFormat" | `templateId` ist kein String.
    `data` ist kein Objekt.
    Weitere Felder haben den falschen Typ. | | 400 Bad Request | "missing" | `templateId` fehlt.
    `data` fehlt. | | 400 Bad Request | "duplicateEntry" | `templateId` oder `chargeId` wurden schon verwendet. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body übergeben. | ### DELETE vouchers/templates/\{templateId} Diese Methode löscht eine bestehende Gutschein-Blaupause (Template) anhand ihrer eindeutigen ID, wobei die ID dem Namen der Blaupause entspricht. Nach erfolgreicher Löschung wird die `templateId` der entfernten Blaupause als Bestätigung zurückgegeben. Für die Ausführung sind Löschberechtigungen für Gutschein-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/templates/myTemplate ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "templateId": "myTemplate" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ---------- | ---------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Gutschein-Daten. | | 400 Bad Request | "notFound" | Die Blaupause wurde nicht gefunden. | ## Methoden für Gutschein-Vorlagen In diesem Abschnitt werden alle Endpunkte zur Verwaltung von Gutschein-Vorlagen beschrieben. Im Gegensatz zu Gutschein-Blaupausen, die flexibel durch Benutzer erstellt und angepasst werden können, handelt es sich bei Gutschein-Vorlagen um standardisierte Strukturen, die bestimmte Typen oder Eigenschaften von Gutscheinen definieren. Vorlagen dienen als Basis für die Erstellung neuer Gutscheine nach festen Vorgaben und sind oft enger an das System gekoppelt. Über die Schnittstelle können diese Vorlagen abgerufen und bei Bedarf angepasst werden. Für alle Operationen sind entsprechende Lese- und Schreibberechtigungen erforderlich. **Hinweis:** Das Feld `presetId` entspricht intern der Spalte `name` in der Datenbank. Trotz dieser Zuordnung darf im Rahmen der API jedoch nicht nach `name` sortiert, gefiltert oder der Wert direkt abgefragt oder gesetzt werden. Alle Vorgänge erfolgen ausschließlich über `presetId`. ### GET vouchers/presets Diese Methode liefert eine paginierte Liste aller vorhandenen Gutschein-Vorlagen (Presets). Über Filter- und Sortierparameter kann die Liste nach Eigenschaften wie Systemstatus oder Erstellungsdatum eingeschränkt und geordnet werden. Die Vorlagen enthalten vordefinierte Einstellungen für die Erstellung neuer Gutscheine. Für den Zugriff sind Leseberechtigungen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/presets ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "createdAt": "1970-01-01T00:33:45.000Z", "data": { ... }, "presetId": "123", "system": false, "updatedAt": "1970-01-01T00:33:45.000Z" } ], "nextPageToken": "MA", "totalCount": 1 } ``` #### Filterfelder `presetId`, `system`, `createdAt`, `updatedAt` #### Sortierfelder `presetId`, `system`, `createdAt`, `updatedAt` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Gutschein-Daten. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET vouchers/presets/labels Diese Methode liefert eine Liste aller vergebenen Labels, die bei Gutschein-Vorlagen (Presets) verwendet wurden. Labels dienen der Kategorisierung von Vorlagen und werden bei der Volltextsuche berücksichtigt. Für den Zugriff auf diese Informationen sind Leseberechtigungen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/presets/labels ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ "label1", "label2" ] ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | -------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte. | ### PUT vouchers/presets/\{presetid} Diese Methode aktualisiert die Eigenschaften einer bestehenden Gutschein-Vorlage (Preset) anhand ihrer eindeutigen ID, wobei die ID dem Namen der Vorlage entspricht. Über den Request-Body werden die neuen Einstellungen der Vorlage übergeben, darunter Rabatttypen, Werte, Nutzungsbedingungen und weitere Attribute. Nach erfolgreicher Aktualisierung wird die ID der geänderten Vorlage zurückgegeben. Schreibberechtigungen für Gutschein-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/presets/oldPresetName ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "data": { "count": 1, "data": { "active": true, "name": "newPresetName", "chargeId": "", "values": [ { "value": 55, "currency": "GBP", "minOrderValue": 100, "taxId": "" } ], "types": { "keepSurplus": false, "discount": true, "freeShipping": false, "maxUseCountPerUser": 1, "maxUseCountSet": true, "multipleCustomer": true, "appOnly": false }, "basketProducts": [], "labels": [], "maxUseCount": 1 } }, "presetId": "newPresetName" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-04-11T13:25:53.000Z", "data": { "count": 1, "data": { "active": true, "name": "newPresetName", "chargeId": "", "values": [ { "value": 55, "currency": "GBP", "minOrderValue": 100, "taxId": "" } ], "types": { "keepSurplus": false, "discount": true, "freeShipping": false, "maxUseCountPerUser": 1, "maxUseCountSet": true, "multipleCustomer": true, "appOnly": false }, "basketProducts": [], "labels": [], "maxUseCount": 1 } }, "presetId": "newPresetName", "system": false, "updatedAt": "2025-04-11T13:25:53.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------------- | ------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Gutschein-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidFormat" | `presetId` ist kein String.
    `data` ist kein Objekt.
    Weitere Felder haben einen falschen Typ. | | 400 Bad Request | "missing" | `presetId` fehlt.
    `data` fehlt. | | 400 Bad Request | "invalidCombination" | `newCustomersOnly` und `existingCustomersOnly` sind gesetzt. | | 400 Bad Request | "readonlyField" | Es ist nicht erlaubt, `disabledFields` zu aktualisieren. | | 400 Bad Request | "duplicateEntry" | `presetId` wurde schon verwendet. | | 400 Bad Request | "notFound" | Die Vorlage wurde nicht gefunden. | | 400 Bad Request | "internalError" | Alte Daten konnten nicht als JSON gelesen werden. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body übergeben. | ### POST vouchers/presets Diese Methode erstellt eine neue Gutschein-Vorlage (Preset) anhand der übermittelten Konfigurationsdaten. Der Request-Body muss eine eindeutige `presetId` sowie ein `data`-Objekt mit den relevanten Gutscheineinstellungen enthalten. Nach erfolgreicher Erstellung wird die ID der neuen Vorlage zurückgegeben. Erstellberechtigungen für Gutschein-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/presets ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "presetId": "cvcv89", "systemPreset": "", "data": { "count": 1, "data": { "active": true, "name": "cvcv89", "chargeId": "", "maxUseCount": 1, "values": [ { "value": 55, "currency": "GBP", "minOrderValue": 55, "taxId": "" } ], "types": { "keepSurplus": false, "discount": true, "freeShipping": false, "maxUseCountPerUser": 1, "maxUseCountSet": true, "multipleCustomer": true, "appOnly": false }, "basketProducts": [], "labels": [] } } } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-04-11T13:25:53.000Z", "data": { "count": 1, "data": { "active": true, "name": "cvcv89", "chargeId": "", "maxUseCount": 1, "values": [ { "value": 55, "currency": "GBP", "minOrderValue": 55, "taxId": "" } ], "types": { "keepSurplus": false, "discount": true, "freeShipping": false, "maxUseCountPerUser": 1, "maxUseCountSet": true, "multipleCustomer": true, "appOnly": false }, "basketProducts": [], "labels": [] } }, "presetId": "cvcv89", "system": false, "updatedAt": "2025-04-11T13:25:53.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Gutschein-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidFormat" | `presetId` ist kein String.
    `data` ist kein Objekt.
    `validFrom` oder `validUntil` enthalten ungültige Zeitpunkte.
    Weitere Felder haben einen falschen Typ. | | 400 Bad Request | "missing" | `presetId` fehlt.
    `data` fehlt. | | 400 Bad Request | "invalidValue" | `presetId` ist leer. | | 400 Bad Request | "invalidCombination" | `newCustomersOnly` und `existingCustomersOnly` sind gleichzeitig gesetzt. | | 400 Bad Request | "readonlyField" | Es ist nicht erlaubt, `disabledFields` zu setzen. | | 400 Bad Request | "duplicateEntry" | `presetId` wurde schon verwendet. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body übergeben. | ### DELETE vouchers/presets/\{presetid} Diese Methode löscht eine bestehende Gutschein-Vorlage (Preset) anhand ihrer eindeutigen ID, wobei die ID dem Namen der Vorlage entspricht. Nach erfolgreicher Löschung wird die ID der entfernten Vorlage als Bestätigung zurückgegeben. Für die Ausführung sind Löschberechtigungen für Gutschein-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/vouchers/presets/myPreset ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "presetId": "myPreset" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ---------- | ---------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Gutschein-Daten. | | 400 Bad Request | "notFound" | Die Vorlage wurde nicht gefunden. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Import Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-import Datenimporte über die Admin Interface API starten, pausieren, fortsetzen, abbrechen und den aktuellen Fortschritt einzelner Services abfragen. Der Endpunkt `import/` stellt eine Schnittstelle für den Import von Daten in das System bereit. Über die API können Importvorgänge gestartet, pausiert, fortgesetzt, abgebrochen und der aktuelle Fortschritt abgefragt werden. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | --------------- | ------------- | --------------------- | ------------------- | --------------------- | --------------------- | | **Import** | import/ | | | | | ## Allgemein ### Unterstützte Services und Formate Der Endpunkt `import/` stellt eine Schnittstelle für den Import von Daten in das System bereit. Über die API können Importvorgänge gestartet, pausiert, fortgesetzt, abgebrochen und der aktuelle Fortschritt abgefragt werden. Aktuell wird die Importfunktion für die folgenden Services unterstützt: | **Service** | **Unterstützte Formate** | | ---------------------- | ------------------------ | | `adminUser` | `json`, `csv` | | `category` | `json`, `csv` | | `customerAccount` | `json`, `csv` | | `dataFeed` | `json`, `csv` | | `dataFeedTemplate` | `json`, `csv` | | `inquiry` | `json`, `csv`, `xml` | | `inventory` | `json`, `csv` | | `order` | `json`, `xml` | | `newsletterSubscriber` | `json`, `csv` | | `product` | `json`, `csv` | | `productRating` | `json`, `csv` | | `seoViews` | `json`, `csv` | | `voucher` | `json`, `csv` | | `voucherPreset` | `json`, `csv` | | `voucherTemplate` | `json`, `csv` | ## Methoden für den Datenimport ### GET import/\{service}/status Dieser Endpunkt liefert den aktuellen Status eines laufenden oder zuletzt ausgeführten Importprozesses für einen angegebenen Service (z. B. `newsletterSubscriber`). Die Antwort enthält Detailinformationen zum Fortschritt, zu verarbeiteten und fehlerhaften Datensätzen, zum Startzeitpunkt sowie – sofern vorhanden – zur Endzeit des Imports. Der Status eines Importvorgangs wird über numerische Werte abgebildet:\ `0 = READY`\ `1 = STARTING`\ `2 = RUNNING`\ `3 = PAUSED`\ `4 = CANCELED`\ `5 = FINISHED`\ `6 = ERROR` Diese Statuswerte geben Aufschluss über den aktuellen Fortschritt oder das Ergebnis eines Imports. Für den Zugriff sind entsprechende Berechtigungen für den jeweiligen Service erforderlich – entweder Schreib- **und** Erstellrechte oder ein Administratorzugang mit Vollzugriff. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/import/newsletterSubscriber/status ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "duration": 2, "end": "", "failed": 0, "globalError": 0, "importErrors": [], "lastError": "", "percentage": 60, "processed": 3, "start": "2025-02-19T13:31:40.000000000Z", "status": 2, "total": 5 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | --------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte des Services. | | 400 Bad Request | | `service` ist unbekannt. | | 503 Service Unavailable | "internalError" | Redis hat keinen Status geliefert. | ### POST import/\{service}/start Dieser Endpunkt startet den Importprozess für einen angegebenen Service. Die hochzuladenden Daten (z. B. als JSON oder CSV) werden im Request-Body übergeben. Falls bereits ein Importprozess für den Service läuft, wird dieser automatisch abgebrochen, bevor der neue Import gestartet wird. Die Antwort liefert unmittelbar den aktuellen Status des gestarteten Imports. Enthalten sind Informationen zum Fortschritt, zur Anzahl verarbeiteter und fehlerhafter Datensätze sowie zu Start- und Endzeiten. Der Statuswert wird als numerische Codierung gemäß der Import-Definition zurückgegeben. Zum Starten eines Imports sind Schreib- und Erstellberechtigungen für den jeweiligen Service erforderlich (z. B. Newsletter). Alternativ ist ein Administratorzugang mit Vollzugriff notwendig. #### Query-Parameter | **Parameter** | **Pflicht** | **Beschreibung** | | ------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `format` | Nein | Das Datenformat der Import-Datei (z. B. `json`, `csv`). Die unterstützten Formate hängen vom jeweiligen Service ab (siehe Abschnitt 2.1). | | `sendMail` | Nein | Nur für den Service `adminUser`: Steuert, ob eine E-Mail an die importierten Benutzer gesendet wird. | #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/import/newsletterSubscriber/start?format=json ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "blacklisted": false, "createdAt": "2025-02-04T15:05:24.000Z", "createdBy": 0, "email": "subscriber@websale.de", "fields": { "firstName": "fda", "lastName": "fafdsa", "salutation": "1" }, "id": 2, "isImport": true, "subshopId": "deutsch", "targetGroupIds": [ 1, 2, 3 ] }, { "blacklisted": true, "createdAt": "2025-02-04T16:06:23.000Z", "createdBy": 1, "email": "foo@example.com", "fields": {}, "id": 3, "isImport": false, "subshopId": "deutsch", "targetGroupIds": [ 1 ] }, ... ] ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "duration": 1, "end": "2025-04-28T11:55:13.000000000Z", "failed": 9, "globalError": 0, "importErrors": [ { "errors": [ { "entryId": "", "error": 0, "field": "salutation" }, { "entryId": "", "error": 0, "field": "lastName" }, { "entryId": "", "error": 0, "field": "firstName" } ], "index": 1 }, { "errors": [ { "entryId": "", "error": 0, "field": "salutation" }, { "entryId": "", "error": 0, "field": "lastName" }, { "entryId": "", "error": 0, "field": "firstName" } ], "index": 3 }, ... ], "lastError": "", "percentage": 100, "processed": 12, "start": "2025-04-28T11:55:12.000000000Z", "status": 5, "total": 12 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben oder Erstellen der Daten des Services. | | 400 Bad Request | | `service` ist unbekannt.
    Der Service unterstützt das `format` nicht. | | 503 Service Unavailable | "serviceUnavailable" | Der Importprozess konnte nicht getriggert werden. | | 503 Service Unavailable | "internalError" | Redis hat keinen Status geliefert.
    Der interne `FileService` kann nicht erreicht werden.
    Request konnte nicht in einer Datei gespeichert werden.
    Der Status konnte nicht in Redis aktualisiert werden.
    Der Importprozess wurde nicht innerhalb von 10 Sekunden gestartet. | ### POST import/\{service}/pause Dieser Endpunkt pausiert einen laufenden Importprozess für einen angegebenen Service. Die Antwort enthält den aktuellen Status des pausierten Prozesses einschließlich der verarbeiteten Datensätze, des Fortschritts und eventueller Fehler. Nach erfolgreichen Pausieren wird der Statuswert auf `PAUSED` (3) gesetzt. Zum Pausieren eines Imports sind Schreib- und Erstellberechtigungen für den jeweiligen Service erforderlich (z. B. Newsletter). Alternativ ist ein Administratorzugang mit Vollzugriff notwendig. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/import/newsletterSubscriber/pause ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "duration": 0, "end": "", "failed": 0, "globalError": 0, "importErrors": [], "lastError": "", "percentage": 60, "processed": 3, "start": "2025-02-19T13:39:17.000000000Z", "status": 3, "total": 5 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte. | | 400 Bad Request | | `service` ist unbekannt. | | 404 Not found | | Der Prozess läuft nicht oder befindet sich nicht im Status RUNNING. | | 503 Service Unavailable | "internalError" | Redis hat keinen Status geliefert.
    Redis kann nicht erreicht werden.
    Der Prozess konnte nicht gestoppt werden. | ### POST import/\{service}/resume Dieser Endpunkt führt einen pausierten Importprozess für einen angegebenen Service fort. Die Antwort enthält den aktuellen Status des fortgeführten Prozesses einschließlich der verarbeiteten Datensätze, des Fortschritts und eventueller Fehler. Zum Fortfahren eines Imports sind Schreib- und Erstellberechtigungen für den jeweiligen Service erforderlich (z. B. Newsletter). Alternativ ist ein Administratorzugang mit Vollzugriff notwendig. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/import/newsletterSubscriber/resume ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "duration": 0, "end": "", "failed": 0, "globalError": 0, "importErrors": [], "lastError": "", "percentage": 60, "processed": 3, "start": "2025-02-19T13:39:17.000000000Z", "status": 2, "total": 5 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte. | | 400 Bad Request | | `service` ist unbekannt. | | 404 Not found | | Der Prozess befindet sich nicht im Status PAUSED. | | 503 Service Unavailable | "internalError" | Redis hat keinen Status geliefert.
    Redis kann nicht erreicht werden.
    Der Prozess konnte nicht gestoppt werden. | ### DELETE import/\{service}/cancel Dieser Endpunkt bricht einen laufenden Importprozess für einen angegebenen Service ab. Die Antwort enthält den aktuellen Status des abgebrochenen Prozesses einschließlich der verarbeiteten Datensätze, des Fortschritts und eventueller Fehler. Nach einem erfolgreichen Abbruch wird der Statuswert auf `CANCELED` (4) gesetzt. Zum Abbrechen eines Imports sind Schreib- und Erstellberechtigungen für den jeweiligen Service erforderlich (z. B. Newsletter). Alternativ ist ein Administratorzugang mit Vollzugriff notwendig. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/import/newsletterSubscriber/cancel ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "duration": 2, "end": "2025-02-19T13:39:19.000000000Z", "failed": 0, "globalError": 0, "importErrors": [], "lastError": "", "percentage": 60, "processed": 3, "start": "2025-02-19T13:39:17.000000000Z", "status": 4, "total": 5 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte. | | 400 Bad Request | | `service` ist unbekannt. | | 404 Not found | | Der Prozess läuft nicht oder befindet sich nicht in einem abbrechbaren Status (RUNNING, STARTING oder PAUSED). | | 503 Service Unavailable | "internalError" | Redis hat keinen Status geliefert.
    Redis kann nicht erreicht werden.
    Der Prozess konnte nicht gestoppt werden. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Kategorien Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-kategorien Kategorien und Kategoriestrukturen über die Admin Interface API erstellen, abrufen, aktualisieren, löschen und Produkte gezielt zuweisen. Erstellen, Abrufen und Zuordnen von Kategorien.Der Endpunkt `categories/` stellt Ihnen eine Schnittstelle bereit mit der Sie Kategorie-Daten in unserem Shop-System verwalten können. Mit dieser Schnittstelle können Sie Kategorien abrufen, erstellen, löschen und Produkte Kategorien zuweisen. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | -------------------- | --------------------- | --------------------- | --------------------- | --------------------- | --------------------- | | **Kategorien** | categories/ | | | | | | **Produktzuweisung** | | | | | | ## Datenfelder eine Kategorie (Category Resource) Die Datenfelder einer Kategorie werden in der Konfiguration verwaltet und intern als JSON-Objekt gespeichert.
    Es wird zwischen folgenden Feldtypen unterschieden: * Standardfelder: Vom System vorgegeben und immer vorhanden (z. B. `id`, `name`, `descr`, `hidden`) * Benutzerdefinierte Felder: Können flexibel angelegt werden und befinden sich im Abschnitt `custom` des Objekts * Technische Felder zur Strukturabbildung: Dienen der Darstellung der Kategoriestruktur im Shop
    Dazu gehören: * `_parent` – ID der übergeordneten Kategorie * `_children` – Liste der untergeordneten Kategorien * `sortValue` – technischer Sortierwert zur Bestimmung der tatsächlichen Reihenfolge im Shop | **Name** | **Typ** | **Bedeutung** | | ---------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------ | | **id** | String | Eindeutige ID der Kategorie | | **name** | String | Anzeigename der Kategorie | | **descr** | String | Beschreibungstext (z. B. zur Anzeige im Frontend) | | **active** | String | Aktivitätsstatus (`"always"`, `"never"`, `"test"` (aktiv nur im Testmodus)) | | **productAssignmentType** | String | Art der Produktzuweisung (`"manual", "ruleBased", "handUp"`) | | **productRules** | String | Geparstes Objekt, das Regeln für Produktzuweisung enthält | | **hidden** | Boolean | Gibt an, ob die Kategorie im Frontend ausgeblendet werden soll | | **timestampCreatedAt** | String | Zeitpunkt, zu dem die Kategorie erstellt wurde (ISO 8601-Format, UTC). | | **timestampUpdatedAt** | String | Zeitpunkt, der letzten Änderung (ISO 8601-Format, UTC). | | **custom** | Objekt | Objekt für benutzerdefinierte Felder | | **custom.\** | Benutzerdefiniert | Benutzerdefiniertes Feld, frei definierbar über die Konfiguration (z. B. `image`, `seoName`, `robotsNoIndex` etc.) | #### Zusätzliche Felder | **Name** | **Typ** | **Bedeutung** | | -------------- | ----------------- | --------------------------------------------------------- | | **\_parent** | String | ID der übergeordneten Kategorie (leer bei Hauptkategorie) | | **\_children** | Array von Strings | Liste der IDs untergeordneter Kategorien | | **sortValue** | Int | Position der Kategorie in dem Shop | #### Beispiel des Datensatzes ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "_children": [ "107-06636", "108-64674" ], "_parent": "", "active": "always", "custom": { "alternativeTemplate": "", "image": [], "robotsNoFollow": false, "robotsNoIndex": false, "seoName": "" }, "descr": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, ...", "hidden": false, "id": "100-14213", "name": "Bekleidung", "productAssignmentType": "manual", "productRules": "[{\"field\":\"active\",\"mode\":\"eq\",\"value\":\"always\"},{\"field\":\"itemNumber\",\"mode\":\"contains\",\"value\":\"5\"}]", "sortValue": 62, "timestampCreatedAt": "2024-01-10T13:36:31.000Z", "timestampUpdatedAt": "2024-09-26T10:41:54.000Z" } ``` **Breaking Change in Antworten.** Kategoriefelder vom Typ `Price` werden nicht mehr als String, sondern als Objekt mit Standardpreis und geplanten Aktionspreisen ausgeliefert. Aufbau, erlaubtes Format in Requests und Validierung sind identisch mit den Produktfeldern und im Abschnitt [Zeitgesteuerte Preise (Aktionspreise)](/schnittstellen/admin-interface-api/api-referenz-produkte#zeitgesteuerte-preise-aktionspreise) beschrieben. ## Methoden für Kategorien ### GET categories Dieser Endpunkt liefert eine Liste von Kategorien aus dem Shopsystem. Eine Sortierung, Textsuche oder komplexe Filterung ist derzeit nicht möglich. Es kann jedoch gezielt nach Unterkategorien einer bestimmten Kategorie gefiltert werden, indem der Parameter `filter[parent]` verwendet wird. Wird `parent=root` gesetzt, werden alle Hauptkategorien der obersten Ebene zurückgegeben. Durch den Parameter `withExternData=yes` können zusätzlich die IDs der übergeordneten Kategorie (`_parent`) sowie der untergeordneten Kategorien (`_children`) mitgeladen werden. Mit `subshopId` lassen sich die Kategorien eines bestimmten Subshops abfragen. Für die Nutzung dieses Endpunkts sind Leseberechtigungen für Kategorie-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/ ``` Beispiel mit `withExternData=yes`, um `_parent` und `_children` mitzuladen: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/?withExternData=yes ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "_children": [], "_parent": "372-87532", "active": "never", "custom": { "alternativeTemplate": "", "image": [], "metaDescription": "", "metaDescriptionSetManually": false, "metaTitle": "", "metaTitleSetManually": false, "regger": "", "robotsNoFollow": false, "robotsNoIndex": false, "seoName": "" }, "descr": "test", "hidden": false, "id": "245-10358", "name": "Neue Kategorie", "productAssignmentType": "manual", "productRules": "", "sortValue": 42, "timestampCreatedAt": "2024-09-17T07:44:56.000Z", "timestampUpdatedAt": "2024-12-16T14:14:42.000Z" }, ... ], "endReached": true, "nextPageToken": "", "totalCount": 7 } ``` #### Filterfelder `parent` #### Sortierfelder `Nicht unterstützt` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Kategorie-Daten. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "invalidCombination" | `pageToken` und `from` sind gleichzeitig gesetzt. | | 400 Bad Request | "illegalOperation" | Es wird versucht, Kategorien nach einem Feld vom Typ `Liste`, `Map`, `Bild` oder `Video` zu filtern.
    Eine ungültige Filteroperation wurde auf ein Enum-Feld angewendet – nur `=` oder `≠` sind erlaubt. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | | 404 Not Found | | Die übergeordnete Kategorie wurde nicht gefunden. | ### GET categories/\{categoryId} Dieser Endpunkt lädt die vollständigen Daten einer einzelnen Kategorie anhand ihrer ID. Optional kann mit dem Parameter `withExternData=yes` zusätzlich die ID der übergeordneten Kategorie (`_parent`) sowie die Liste aller direkt untergeordneten Kategorien (`_children`) mitgeliefert werden. Für die Nutzung des Endpunkts sind Leseberechtigungen für Kategorie-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/942-53775 ``` Beispiel mit `withExternData=yes`, um `_parent` und `_children` mitzuladen: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/942-53775?withExternData=yes ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "_children": [], "_parent": "", "active": "always", "custom": { "alternativeTemplate": "", "image": [], "metaDescription": "", "metaDescriptionSetManually": false, "metaTitle": "", "metaTitleSetManually": false, "regger": "", "robotsNoFollow": false, "robotsNoIndex": false, "seoName": "" }, "descr": "123", "hidden": false, "id": "942-53775", "name": "Neue Kategorie", "productAssignmentType": "manual", "productRules": "", "sortValue": 42, "timestampCreatedAt": "2024-09-25T15:03:15.000Z", "timestampUpdatedAt": "2024-12-16T14:14:43.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Kategorie-Daten. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig. | | 404 Not Found | | Es gibt keine Kategorie mit `id`=`categoryId`. | ### PUT categories/\{categoryId} Mit diesem Endpunkt kann eine bestehende Kategorie anhand ihrer ID aktualisiert werden. Der Request-Body muss nur die Felder enthalten, die tatsächlich geändert werden sollen – eine vollständige Kategorie-Definition ist nicht erforderlich. Wird der optionale Parameter `createMissing=yes` gesetzt und existiert keine Kategorie mit der angegebenen ID, wird stattdessen eine neue Kategorie mit dieser ID angelegt. Für die Nutzung dieses Endpunkts sind Schreibberechtigungen für Kategorie-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/1081-68843 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "custom": { "robotsNoFollow": true }, "active": "always", "descr": "My new description" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": "always", "custom": { "alternativeTemplate": "", "image": [], ... }, "descr": "My new description", "hidden": false, "id": "1081-68843", "name": "Bekleidung", "productAssignmentType": "manual", "productRules": "", "timestampCreatedAt": "2024-01-10T13:36:31.000Z", "timestampUpdatedAt": "2025-05-02T14:22:10.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Kategorie-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig.
    Ein Feld vom Typ `Enumeration` enthält einen Wert, der nicht in der Menge von möglichen Werten enthalten ist.
    Ein Bild hat einen Format, der nicht unterstützt wird. | | 400 Bad Request | "invalidFormat" | `custom` ist kein Objekt.
    Ein Feld enthält den Wert `null`.
    Ein Wert hat den Typ, der mit dem Typ aus der Konfiguration nicht übereinstimmt.
    Ein Preis-Wert kann nicht geparst werden.
    Ein Feld vom Typ `Map` hat einen Schlüssel, der kein String ist.
    Ein Feld vom Typ `List` ist kein Array von Strings.
    Ein Zeitwert ist nicht in ISO 8601 Format.
    Bild-Daten von einem Bild sind kein Array von Objekten.
    `id` des Formats oder `path` sind keine Strings. | | 400 Bad Request | "unknownDataField" | Es wird versucht, ein unbekanntes Feld zu aktualisieren.
    Bild-Daten enthalten etwas außer `id` und `path`. | | 400 Bad Request | "notManualEditable" | In der Konfiguration wurde manuelles Bearbeiten verboten. | | 404 Not Found | | Die Kategorie mit `id`=`{categoryId}` wurde nicht gefunden und der Parameter `createMissing` ist nicht auf `yes` gesetzt. | | 503 Service Unavailable | "internalError" | Die Aktualisierung ist fehlgeschlagen. | ### PUT categories/\{categoryId}/assign Mit diesem Endpunkt können einer bestehenden Kategorie anhand ihrer ID mehrere Unterkategorien zugewiesen werden. Der spezielle Wert `categoryId`: "root" sorgt dafür, dass die Kategorien als **Hauptkategorien** auf die oberste Ebene kommen. Im Request-Body muss ein Array von Kategorie-IDs übergeben werden, die der angegebenen Kategorie als untergeordnet (`_children`) zugeordnet werden sollen. Für die Nutzung dieses Endpunkts sind Schreibberechtigungen für Kategorie-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/1081-68843/assign ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "categoryIds": [ "1032-22182", "109-30589", "105-09206" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Kategorie-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig. | | 404 Not Found | | Die Kategorie mit `id`=`{categoryId}` wurde nicht gefunden. | | 400 Bad Request | "unknownDataField" | Es wurde etwas außer `categoryIds` übergeben. | | 400 Bad Request | "invalidFormat" | `categoryIds` ist kein Array von Strings. | ### POST categories/\{categoryId}/move Mit diesem Endpunkt kann eine bestehende Kategorie anhand ihrer ID innerhalb der Kategoriestruktur verschoben werden. Die Positionierung erfolgt entweder durch Einordnung als Unterkategorie (`intoTarget`) oder durch Sortierung auf derselben Ebene (`beforeTarget` oder `afterTarget`). Es darf nur einer dieser Zielparameter gesetzt sein. Für die Nutzung dieses Endpunkts sind Schreibberechtigungen für Kategorie-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/1081-68843/move ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "beforeTarget": "1080-40793" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": "never", "custom": { "alternativeTemplate": "", "defaultSort": "", "image": [], "metaDescription": "", "metaDescriptionSetManually": false, "metaTitle": "", "metaTitleSetManually": false, "robotsNoFollow": false, "robotsNoIndex": false, "seoName": "", "video": "" }, "descr": "test", "hidden": false, "id": "1081-68843", "name": "Neue Kategorie", "productAssignmentType": "manual", "productRules": "", "timestampCreatedAt": "2025-05-02T13:59:38.000Z", "timestampUpdatedAt": "2025-05-02T13:59:38.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Kategorie-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig.
    Die neue Position ist in einer Unterkategorie der Kategorie, die verschoben werden soll. | | 400 Bad Request | "missing" | Es fehlt ein Target-Parameter (`intoTarget`, `beforeTarget`, `afterTarget`). | | 400 Bad Request | "invalidFormat" | `intoTarget`, `beforeTarget` oder `afterTarget` sind keine Strings. | | 400 Bad Request | "unknownDataField" | Request body enthält etwas außer `intoTarget`, `beforeTarget`, `afterTarget`. | | 400 Bad Request | "invalidCombination" | Mehrere Target-Parameter (`intoTarget`, `beforeTarget`, `afterTarget`) können nicht gleichzeitig gesetzt werden. | | 404 Not Found | | Die Kategorie mit `id`=`{categoryId}` wurde nicht gefunden.
    "Target" enthält keine gültige Id. | ### POST categories/\{categoryId}/setRule Mit diesem Endpunkt können einer bestehenden Kategorie anhand ihrer ID mehrere Produkte zugewiesen werden. Im Request-Body muss ein als JSON serialisiertes Array von Regeln übergeben werden. Produkte, auf die die Regeln zutreffen, werden der Kategorie zugewiesen. `rebuilt` in der Antwort gibt an, ob die Regel sofort angewendet werden konnte. Wenn der Wert `false` ist, wird es später erneut versucht – der Endpunkt muss dafür nicht erneut getriggert werden. Für die Nutzung dieses Endpunkts sind Schreibberechtigungen für Kategorie-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/1081-68843/setRule ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "rule": "[{\"field\":\"name\",\"mode\":\"contains\",\"value\":\"h\"},{\"field\":\"price\",\"mode\":\"lt\",\"value\":\"100\"}]" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "count": 167, "rebuilt": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Kategorie-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden.
    Die Regel funktioniert nicht.
    Diese Regel trifft auf zu viele Produkte zu. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig. | | 404 Not Found | | Die Kategorie mit `id`=`{categoryId}` wurde nicht gefunden. | | 400 Bad Request | "invalidFormat" | `rule` ist kein String. | | 400 Bad Request | "unknownDataField" | Request body enthält etwas außer `rule`. | ### POST categories/rebuildRules Dieser Endpunkt aktualisiert Produkte in Kategorien mit regelbasierter Produktzuweisung. Für die Nutzung dieses Endpunkts sind Schreibberechtigungen für Kategorie-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/rebuildRules ``` #### Request Body ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Kategorie-Daten. | | 503 Service Unavailable | "internalError" | Die interne URL des Rebuilder-Programms ist nicht gesetzt.
    Das Rebuilder-Programm konnte nicht gestartet werden. | ### POST categories Mit diesem Endpunkt kann eine neue Kategorie im Shop-System erstellt werden.
    Über die optionalen Parameter `intoTarget`, `beforeTarget` oder `afterTarget` lässt sich festlegen, wo die neue Kategorie in der Kategoriestruktur einsortiert werden soll: * Mit `intoTarget` wird sie als Unterkategorie einer bestehenden Kategorie angelegt. * Der spezielle Wert `intoTarget: "root"` sorgt dafür, dass die neue Kategorie als **Hauptkategorie** auf der obersten Ebene erstellt wird. * Mit `beforeTarget` oder `afterTarget` wird sie auf derselben Ebene vor oder nach einer vorhandenen Kategorie einsortiert. Es darf jeweils nur ein Zielparameter gesetzt sein. Für die Nutzung dieses Endpunkts sind Erstellberechtigungen für Kategorie-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/ ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "Neue Kategorie", "intoTarget": "root" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": "never", "custom": { "alternativeTemplate": "", "image": [], "metaDescription": "", "metaDescriptionSetManually": false, "metaTitle": "", "metaTitleSetManually": false, ... }, "descr": "", "hidden": false, "id": "1080-40793", "name": "Neue Kategorie", "productAssignmentType": "manual", "productRules": "", "timestampCreatedAt": "", "timestampUpdatedAt": "" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Kategorie-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig.
    "Target" enthält keine gültige Id.
    Ein Feld vom Typ `Enumeration` enthält einen Wert, der nicht in der Menge von möglichen Werten enthalten ist.
    Ein Bild hat einen Format, der nicht unterstützt wird. | | 400 Bad Request | "invalidCombination" | Mehrere Target-Parameter (`intoTarget`, `beforeTarget`, `afterTarget`) können nicht gleichzeitig gesetzt werden. | | 400 Bad Request | "invalidFormat" | `custom` ist kein Objekt.
    Ein Feld enthält den Wert `null`.
    Ein Wert hat den Typ, der mit dem Typ aus der Konfiguration nicht übereinstimmt.
    Ein Preis-Wert kann nicht geparst werden.
    Ein Feld vom Typ `Map` hat einen Schlüssel, der kein String ist.
    Ein Feld vom Typ `List` ist kein Array von Strings.
    Ein Zeitwert ist nicht in ISO 8601 Format.
    Bild-Daten von einem Bild sind kein Array von Objekten.
    `id` des Formats oder `path` sind keine Strings. | | 400 Bad Request | "unknownDataField" | Es wird versucht, ein unbekanntes Feld zu aktualisieren.
    Bild-Daten enthalten etwas außer `id` und `path`. | | 400 Bad Request | "notManualEditable" | In der Konfiguration wurde manuelles Bearbeiten verboten. | ### DELETE categories/\{categoryId} Mit diesem Endpunkt kann eine bestehende Kategorie anhand ihrer ID gelöscht werden.
    Dabei werden nicht nur die gewählte Kategorie selbst, sondern auch alle zugehörigen Unterkategorien aus dem System entfernt. Für die Nutzung dieses Endpunkts sind Löschberechtigungen für Kategorie-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/1081-68843 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ---------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Kategorie-Daten. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig. | | 404 Not Found | | Die Kategorie wurde nicht gefunden. | ## Methoden für Produktzuweisung ### Technische Limits Produkte können Kategorien manuell, regelbasiert oder über die Unterkategorien zugewiesen werden: * **Manuelle Zuweisung** bedeutet, dass bestimmte Produkte gezielt einzelnen Kategorien zugeordnet werden (z. B. „Produkt A gehört zu Kategorie B“). * **Regelbasierte Zuweisung** erlaubt es, Kategorien automatisch mit Produkten zu befüllen, die bestimmte Kriterien erfüllen (z. B. „alle reduzierten Produkte“ oder „alle Produkte mit Lagerbestand > 0“). * **Produkte von Unterkategorien übernehmen**, hiermit werden Kategorien automatisch mit allen Produkten befüllt, die den direkten Unterkategorien zugewiesen sind. Z. B. die Kategorie "Damen" enthält alle Produkte aus den Unterkategorien "Damenblusen" und "Damenröcke". Bei regelbasierten Kategorien ist die **maximale Anzahl an zugewiesenen Produkten technisch auf 1.000 Ergebnisse begrenzt**, unabhängig von der Anzahl der Produkte im Shop oder von der formulierten Regel. Wenn Produkte über mehrere Hierarchie-Ebenen übernommen werden sollen, müssen alle Kategorieebenen ihre Produkte ebenfalls aus den Unterkategorien übernehmen. Andernfalls werden nur die Produkte der direkten Unterkategorie übernommen, aber nicht die Produkte deren Kinder. Beispiel: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} |-Kategorie A (Produkte von Unterkategorien übernehmen) | |-Kategorie B (Manuell) | | |-Kategorie C (Manuell) | |-Kategorie D (Produkte von Unterkategorien übernehmen) | | |-Kategorie E (Regelbasiert) | | |-Kategorie F (Manuell) | |- Kategorie G (Regelbasiert) ``` Kategorie A bekommt alle Produkte aus den Kategorien B, D, E, F und G zugeordnet. Die Produkte aus Kategorie C werden Kategorie A jedoch nicht zugeordnet, da die Produktzuweisung für Kategorie B "Manuell" ist und nicht "Produkte von Unterkategorien übernehmen". ### GET categories/\{categoryId}/products Mit diesem Endpunkt wird eine Liste aller Produkte abgerufen, die einer bestimmten Kategorie anhand ihrer ID zugewiesen sind. Die Parameter `from` und `size` dienen der Aufteilung großer Ergebnismengen in Seiten – damit die API nicht z. B. 10.000 Produkte auf einmal übertragen muss. `from` gibt an, wie viele Einträge am Anfang übersprungen werden, `size` bestimmt die maximale Anzahl der zurückgegebenen Produkte. Zusätzlich kann mit dem optionalen Parameter `textSearch` eine Textsuche innerhalb der zugewiesenen Produkte durchgeführt werden. Für die Nutzung dieses Endpunkts sind Leseberechtigungen für Kategorie-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/105-09206/products?from=0&size=50 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "active": "never", "custom": { "brand": "", "commission": 0, "commissionTaxRate": "", ... }, "descr": "SUPER COOL PRODUCT", "id": "100-41232", "itemNumber": "999999999", "name": "Something", "price": "0.000000", "taxRateId": "7", "timestampCreatedAt": "2024-09-11T09:01:15.000Z", "timestampUpdatedAt": "2024-12-16T14:20:41.000Z" }, ... ], "totalCount": 8 } ``` #### Filterfelder `nicht unterstützt` #### Sortierfelder `productId` (muss nicht explizit angegeben werden. `sort:asc` bzw. `sort:desc` reicht aus) #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Kategorie-Daten. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET categories/products/unassigned Mit diesem Endpunkt wird eine Liste aller Produkte abgerufen, die aktuell keiner Kategorie zugewiesen sind. Die Parameter `from` und `size` dienen der Aufteilung großer Ergebnismengen in Seiten – damit die API nicht z. B. 10.000 Produkte auf einmal übertragen muss. `from` gibt an, wie viele Einträge am Anfang übersprungen werden, `size` bestimmt die maximale Anzahl der zurückgegebenen Produkte. Der optionale Parameter `textSearch`ermöglicht eine Textsuche innerhalb der nicht zugewiesenen Produkte. Für die Nutzung dieses Endpunkts sind Leseberechtigungen für Kategorie-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/products/unassigned?from=0&size=50 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "active": "never", "custom": { "brand": "", "commission": 0, "commissionTaxRate": "", ... }, "descr": "", "id": "124-28218", "itemNumber": "", "name": "Neues Produkt", "price": "0.000000", "taxRateId": "", "timestampCreatedAt": "2024-09-26T10:50:23.000Z", "timestampUpdatedAt": "2024-12-16T14:14:42.000Z" }, ... ], "totalCount": 15 } ``` #### Filterfelder `nicht unterstützt` #### Sortierfelder `productId (muss nicht explizit angegeben werden.`sort:asc`bzw.`sort:desc` reicht aus)` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Kategorie-Daten. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### POST categories/\{categoryId}/products/assign Mit diesem Endpunkt können ein oder mehrere Produkte anhand ihrer Produkt-IDs einer bestimmten Kategorie anhand ihrer Kategorie-ID zugewiesen werden. Die Produkt-IDs werden im Feld `prodId` übergeben – entweder als String (ein einzelnes Produkt) oder als Array von Strings (mehrere Produkte). Optional kann mit den Parametern `beforeTarget` oder `afterTarget` festgelegt werden, an welcher Position innerhalb der Kategorie die Produkte einsortiert werden sollen. Beide dürfen nicht gleichzeitig gesetzt sein. Für die Nutzung dieses Endpunkts sind Schreibberechtigungen für Kategorie-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/105-09206/products/assign ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "prodId": [ "111-28077", "110-64564" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Kategorie-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig. | | 400 Bad Request | "invalidFormat" | `prodId` ist kein Array von Strings und kein String.
    `beforeTarget` oder `afterTarget` sind keine Strings. | | 400 Bad Request | "unknownDataField" | Ein anderes Feld außer `prodId`, `beforeTarget` oder `afterTarget` wurde übergeben. | | 400 Bad Request | "missing" | Keine Produkt-ID wurde übergeben. | | 404 Not Found | "missingCategory" | Die Kategorie wurde nicht gefunden. | | 404 Not Found | "missingTarget" | Die Position innerhalb der Kategorie ist ungültig. | | 409 Conflict | "multipleTargets" | `beforeTarget` und `afterTarget` wurden gleichzeitig gesetzt. | | 409 Conflict | "entityNotFound" | Man versucht, ein Produkt, das nicht existiert, zuzuweisen. | ### POST categories/\{categoryId}/products/swap Dieser Endpunkt ermöglicht es, die Position von zwei Produkten innerhalb einer bestimmten Kategorie zu tauschen. Die Produkt-IDs werden im Request-Body übergeben. Die Antwort gibt zurück, ob der Tausch erfolgreich durchgeführt werden konnte. Für die Nutzung dieses Endpunkts sind Schreibrechte für Kategorie-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/105-09206/products/swap ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "productId1": "111-28077", "productId2": "110-64564" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Kategorie-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig. | | 400 Bad Request | "invalidFormat" | `productId1` oder `productId2` sind keine Strings. | | 400 Bad Request | "missing" | `productId1` oder `productId2` fehlen. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde übergeben. | | 404 Not Found | "missingCategory" | Die Kategorie wurde nicht gefunden. | ### DELETE categories/\{categoryId}/products/\{productId} Mit diesem Endpunkt wird ein Produkt anhand seiner ID aus einer bestimmten Kategorie anhand ihrer ID entfernt. Dadurch wird die Verknüpfung zwischen Produkt und Kategorie aufgehoben – das Produkt bleibt im System bestehen, ist jedoch nicht mehr dieser Kategorie zugeordnet. Für die Nutzung dieses Endpunkts sind Schreibberechtigungen für Kategorie-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/105-09206/products/123456 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ----------------- | ------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Kategorie-Daten. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig. | | 404 Not Found | "missingCategory" | Die Kategorie wurde nicht gefunden. | | 404 Not Found | "missingProduct" | Das Produkt wurde nicht gefunden. | ### DELETE categories/\{categoryId}/products/ Mit diesem Endpunkt können mehrere Produkte gleichzeitig aus einer bestimmten Kategorie anhand ihrer ID entfernt werden. Die zu entfernenden Produkt-IDs werden im Feld `prodId` als Array übergeben.
    Dadurch wird die Zuordnung der Produkte zur angegebenen Kategorie aufgehoben – die Produkte selbst bleiben im System erhalten. Für die Nutzung dieses Endpunkts sind Schreibberechtigungen für Kategorie-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/categories/105-09206/products/ ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "prodId": [ "111-28077", "110-64564" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Kategorie-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig. | | 400 Bad Request | "invalidFormat" | Ein Produktindex ist kein String.
    `prodId` ist kein Array. | | 400 Bad Request | "unknownDataField" | Ein anderes Feld außer `prodId` wurde übergeben. | | 400 Bad Request | "missing" | `prodId` fehlt. | | 404 Not Found | "missingCategory" | Die Kategorie wurde nicht gefunden. | ### Ergänzende Referenzen * [API-Referenz Produkte](/schnittstellen/admin-interface-api/api-referenz-produkte) * [API-Referenz Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) * [content - Katalog (Kategorien & Produkte)](/konfiguration/content-katalog-kategorien-produkte) ### Hinweis zu Kategoriedatenfeldern Neue Kategoriedatenfelder (zusätzliche Beschreibungen, Bilder etc.) können nicht direkt über die Kategorie-API erstellt werden. Die API dient ausschließlich dem Auslesen und Pflegen vorhandener Felder. Um neue Felder zu definieren, muss die Konfiguration im Knoten `content.customCategoryField` verwendet werden. → [content - Katalog (Kategorien & Produkte)](/konfiguration/content-katalog-kategorien-produkte) Dort lassen sich individuelle Felder. Sobald ein Feld dort konfiguriert wurde, steht es anschließend automatisch in der Produkt-API zur Verfügung (z. B. in `GET categories` oder `POST categories`). ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Key-Value-Store Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-key-value-store Redis-basierten Key-Value-Store über die Admin Interface API verwalten: Schlüssel-Wert-Paare und Schlüssel-Gruppen anlegen, abrufen und löschen. Der Endpunkt `storage/` stellt eine Schnittstelle zur Verfügung, mit der Key-Value-Paare in einem Redis-basierten Speicher verwaltet werden können. Neben der direkten Speicherung einzelner Schlüssel-Werte-Paare bietet die API die Möglichkeit, diese Einträge zu logischen Gruppen zusammenzufassen, um eine strukturierte Organisation und gezielte Abfragen zu ermöglichen. Unterstützt werden das Erstellen, Abrufen, Aktualisieren und Löschen sowohl einzelner Einträge als auch ganzer Gruppen. Die API eignet sich insbesondere für temporäre Konfigurationsdaten, Zwischenspeicher oder statusbezogene Informationen im Shop-System. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | --------------------- | -------------- | --------------------- | --------------------- | --------------------- | --------------------- | | **Key-Value-Paare** | storage/keys | | | | | | **Schlüssel-Gruppen** | storage/groups | | | | | ## Schlüssel-Gruppen ### Datenfelder einer Schlüssel-Gruppe | **Name** | **Typ** | **Verwendung** | | --------------- | ------- | ------------------------------------------------------------ | | **createdAt** | String | Zeitpunkt der Erstellung (ISO 8601-Format, UTC). | | **description** | String | Beschreibung der Gruppe. | | **id** | Integer | Eindeutige ID der Gruppe. | | **keysArray** | Array | Namen von Schlüsseln, die zu der Gruppe gehören. | | **name** | String | Name der Gruppe. | | **updatedAt** | String | Zeitpunkt der letzten Aktualisierung (ISO 8601-Format, UTC). | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-02-17 15:49:33", "description": "myDescription", "id": 1, "keysArray": [ "asdf", "foo" ], "name": "myGroup", "updatedAt": "2025-02-17 15:49:34" } ``` ## Methoden für Key-Value-Paare Dieser Abschnitt beschreibt die Endpunkte zur Verwaltung einzelner Key-Value-Paare im Key-Value-Store des Systems. Über die API können Einträge erstellt, abgerufen, aktualisiert und gelöscht werden. Optional kann ein Ablaufdatum (TTL) gesetzt werden, um Werte zeitlich begrenzt zu speichern. ### GET storage/keys Mit diesem Endpunkt wird eine Liste aller im System gespeicherten Key-Value-Paare abgerufen. Die Werte werden zusammen mit dem zugehörigen Schlüssel (`key`), dem zugehörigen Wert (`value`) und einem optionalen Ablaufdatum **(**`expirationDate`**)** ausgegeben. Dieser Endpunkt ermöglicht damit eine Übersicht über alle aktuell vorhandenen Einträge im Key-Value-Store. Es gibt keine Sortier- und Filterfelder – die Liste der Parameter steht fest. Bei `textSearch` wird der Name des Schlüssels berücksichtigt, bei `filter_contains[value]` nicht. `filter_contains[value]` kann auch mehrfach vorkommen. Andere Parameter funktionieren genauso wie bei Standard-GET-Anfragen. Für die Nutzung dieses Endpunkts sind Leseberechtigungen für Key-Value-Store-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/storage/keys ``` #### Unterstützte Parameter `size`, `filter_gte[expirationDate]`, `filter_lte[expirationDate]`, `filter_eq[group]`, `pageToken`, `textSearch`, `filter_contains[value]`, `sort` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": false, "items": [ { "expirationDate": "2026-02-18T09:27:09.868Z", "key": "asdf", "value": "asdf" }, { "expirationDate": "2026-02-18T09:24:38.868Z", "key": "test", "value": "test123" } ], "nextPageToken": "", "totalCount": 2 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | -------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Key-Value-Store-Daten. | | 400 Bad Request | "invalidFormat" | Die ID der Gruppe bei `filter_eq[group]` ist keine positive Ganzzahl.
    `size` ist keine positive Ganzzahl. | | 503 Service Unavailable | "internalError" | Der interne `RedisService` kann nicht erreicht werden. | ### GET storage/keys/\{key} Mit diesem Endpunkt kann ein einzelnes Key-Value-Paar anhand seines Schlüssels (`key`) abgerufen werden. Die Antwort enthält den gespeicherten Wert (`value`) sowie optional ein Ablaufdatum **(**`expirationDate`**)**, sofern dieses gesetzt wurde. Für die Nutzung dieses Endpunkts sind Leseberechtigungen für Key-Value-Store-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/storage/keys/asdf ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "expirationDate": "2025-02-20T15:49:19.169Z", "key": "asdf", "value": "asdf" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | -------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Key-Value-Store-Daten. | | 400 Bad Request | "invalidFormat" | `{key}` enthält Sonderzeichen, die nicht zu `{'_', '-', '/', '.', ':', ' '}` gehören. | | 400 Bad Request | "missing" | `{key}` wurde nicht übergeben. | | 404 Not Found | | Der Schlüssel wurde in Redis nicht gefunden. | | 503 Service Unavailable | "internalError" | Der interne `RedisService` kann nicht erreicht werden. | ### POST storage/keys Mit diesem Endpunkt kann ein neues Key-Value-Paar im Key-Value-Store gespeichert werden. Der Schlüssel (`key`) und der zugehörige Wert (`value`) werden im Request Body übergeben.\ Optional kann mit `ttlDays` eine Lebensdauer in Tagen angegeben werden, nach deren Ablauf der Eintrag automatisch gelöscht wird (TTL = Time To Live). Wenn das Key-Value-Paar bereits existiert, wird es überschrieben. Für die Nutzung dieses Endpunkts sind Erstellberechtigungen für Key-Value-Store-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/storage/keys ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "key": "foo", "value": "bar", "ttlDays": 2 } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "key": "foo", "ttl": 172800, "ttlDays": 2, "value": "bar" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Key-Value-Store-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body übergeben. | | 400 Bad Request | "missing" | `key` oder `value` fehlen. | | 400 Bad Request | "invalidValue" | `key` oder `value` sind leer. | | 400 Bad Request | "invalidFormat" | `key` enthält Sonderzeichen, die nicht zu `{'_', '-', '/', '.', ':', ' '}` gehören.
    `key`, `value` oder `ttlDays` haben einen ungültigen Typ. `ttlDays` muss eine positive ganze Zahl sein. | | 503 Service Unavailable | "internalError" | Der interne `RedisService` kann nicht erreicht werden.
    Der Wert konnte nicht gespeichert werden. | ### DELETE storage/keys/\{key} Mit diesem Endpunkt wird ein vorhandenes Key-Value-Paar anhand seines Schlüssels (`key`) dauerhaft aus dem Key-Value-Store entfernt. Bei Erfolg wird ein JSON-Objekt mit `success: true` zurückgegeben. Für die Nutzung dieses Endpunkts sind Löschberechtigungen für Key-Value-Store-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/storage/keys/asdf ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Key-Value-Store-Daten. | | 400 Bad Request | "invalidFormat" | `{key}` enthält Sonderzeichen, die nicht zu `{'_', '-', '/', '.', ':', ' '}` gehören. | | 400 Bad Request | "missing" | `{key}` wurde nicht übergeben. | | 503 Service Unavailable | "internalError" | Der interne `RedisService` kann nicht erreicht werden. | ## Methoden für Schlüssel-Gruppen Schlüssel-Gruppen dienen der logischen Bündelung mehrerer Key-Value-Paare.\ Die hier beschriebenen Endpunkte ermöglichen es, Gruppen anzulegen, zu bearbeiten, abzurufen oder zu löschen. Eine Gruppe enthält Metainformationen wie Name, Beschreibung und eine Liste zugehöriger Schlüssel. ### GET storage/groups Mit diesem Endpunkt wird eine Liste aller im System definierten Schlüssel-Gruppen abgerufen.\ Eine Schlüssel-Gruppe ist eine logische Sammlung mehrerer Key-Value-Paare, die unter einem gemeinsamen Gruppennamen verwaltet werden. Die Antwort enthält u. a. den Namen der Gruppe (`name`), die Anzahl der enthaltenen Schlüssel (`numKeys`) sowie Erstell- und Änderungszeitpunkte. Zur Ergebnissteuerung stehen Filter- und Sortierfunktionen zur Verfügung. Für die Nutzung dieses Endpunkts sind Leseberechtigungen für Key-Value-Store-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/storage/groups/ ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "createdAt": "2025-02-17 15:49:33", "description": "", "id": 1, "keysArray": [ "asdf" ], "name": "qwerty", "numKeys": 1, "updatedAt": "2025-02-17 15:49:34" }, ... ], "nextPageToken": "MA", "totalCount": 1 } ``` #### Filterfelder `keysArray` #### Sortierfelder `numKeys`, `name`, `createdAt`, `updatedAt` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | -------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Key-Value-Store-Daten. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET storage/groups/\{id} Mit diesem Endpunkt kann eine einzelne Schlüssel-Gruppe anhand ihrer ID geladen werden. Die Antwort enthält alle verfügbaren Metadaten zur Gruppe, darunter der Gruppenname (`name`), eine optionale Beschreibung (`description`) sowie eine Liste der zugehörigen Schlüssel (`keysArray`). Für die Nutzung dieses Endpunkts sind Leseberechtigungen für Key-Value-Store-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/storage/groups/1 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-02-17 15:49:33", "description": "", "id": 1, "keysArray": [ "asdf" ], "name": "qwerty", "updatedAt": "2025-02-17 15:49:34" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | -------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Key-Value-Store-Daten. | | 400 Bad Request | "missing" | `id` wurde nicht übergeben. | | 503 Service Unavailable | "internalError" | `id` ist ungültig. | | 404 Not Found | | Die Gruppe mit `id`=`{id}` wurde nicht gefunden. | ### POST storage/groups Mit diesem Endpunkt wird eine neue Schlüssel-Gruppe erstellt. Eine Schlüssel-Gruppe besteht aus einem eindeutigen Namen (`name`), einer optionalen Beschreibung (`description`) und einer Liste von zugeordneten Schlüsseln (`keysArray`). Die Gruppe kann zur strukturierten Verwaltung und Gruppierung mehrerer Key-Value-Einträge verwendet werden. Für die Nutzung dieses Endpunkts sind Erstellberechtigungen für Key-Value-Store-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/storage/groups ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "myGroup", "description": "Group description", "keysArray": [ "asdf", "foo" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "description": "Group description", "id": 3, "keysArray": [ "asdf", "foo" ], "name": "myGroup" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Key-Value-Store-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body übergeben. | | 400 Bad Request | "missing" | `name` oder `keysArray` fehlen. | | 400 Bad Request | "invalidValue" | `name` ist leer. | | 400 Bad Request | "invalidFormat" | `name` oder `description` sind kein String oder `keysArray` ist kein Array. | ### PUT storage/groups/\{id} Mit diesem Endpunkt kann eine bestehende Schlüssel-Gruppe anhand ihrer ID aktualisiert werden. Dabei können der Gruppenname (`name`), die Beschreibung (`description`) und die zugehörigen Schlüssel (`keysArray`) geändert oder neu gesetzt werden. Für die Nutzung dieses Endpunkts sind Schreibberechtigungen für Key-Value-Store-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/storage/groups/1 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "description": "myDescription", "keysArray": [ "asdf", "foo" ], "name": "qwerty" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "description": "myDescription", "keysArray": [ "asdf", "foo" ], "name": "qwerty" } ``` #### Fehlercode | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | ------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Key-Value-Store-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body übergeben. | | 400 Bad Request | "missing" | `id`, `name` oder `keysArray` fehlen. | | 400 Bad Request | "invalidValue" | `name` ist leer. | | 400 Bad Request | "invalidFormat" | `name` oder `description` sind kein String oder `keysArray` ist kein Array. | | 503 Service Unavailable | "internalError" | `id` ist ungültig. | ### DELETE storage/groups/\{id} Mit diesem Endpunkt wird eine bestehende Schlüssel-Gruppe anhand ihrer ID gelöscht. Die zugehörigen Key-Value-Einträge bleiben dabei im System erhalten, es wird lediglich die Gruppenzuordnung entfernt. Bei Erfolg wird ein JSON-Objekt mit `success: true` zurückgegeben. Für die Nutzung dieses Endpunkts sind Löschberechtigungen für Key-Value-Store-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/storage/groups/1 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercode | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Key-Value-Store-Daten. | | 400 Bad Request | "missing" | `id` wurde nicht übergeben. | | 503 Service Unavailable | "internalError" | `id` ist ungültig. | | 404 Not Found | | Die Gruppe mit `id`=`{id}` wurde nicht gefunden. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Konfiguration Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-konfiguration Shopkonfiguration über die Admin Interface API verwalten: globale Einstellungen und subshopspezifische Konfigurationsknoten lesen und schreiben. Die Schnittstelle für den Endpunkt `config/` ermöglicht den umfassenden Zugriff auf die Shopkonfiguration. Über die REST API lassen sich Konfigurationsdaten abrufen, ändern, löschen oder neu anlegen. Dies umfasst sowohl globale Einstellungen als auch subshopspezifische Überschreibungen. Die Konfiguration basiert auf vordefinierten Schemas, die bestimmen, welche Daten zulässig sind. Änderungen an Konfigurationsknoten werden serverseitig auf Gültigkeit geprüft. Die REST API erlaubt damit die vollständige Verwaltung der Shopkonfiguration – wie sie auch über das Admin-Interface vorgenommen wird. ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | --------------------- | --------------------- | --------------------- | | [**Einstellungen**](https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3058532670/API-Referenz+Konfiguration#3-methoden-für-einstellungen) | config/ | | | | | | [**Knoten im Shop**](https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3058532670/API-Referenz+Konfiguration#4-methoden-für-die-verwaltung-von-knoten-im-shop) | | | | | | | | [**Knoten in Subshops**](https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3058532670/API-Referenz+Konfiguration#5-methoden-für-die-verwaltung-von-knoten-in-subshops) | | | | | ## Struktur & Anwendung der Konfiguration über die API Die Shopkonfiguration ist als gerichteter Graph organisiert. Jeder Knoten in diesem Graphen repräsentiert einen eigenständigen Konfigurationsbereich und kann andere Knoten referenzieren – beispielsweise um eine Sprache oder ein Land anzugeben. Jeder Konfigurationsknoten hat einen klar definierten Typ, für den ein Schema festlegt, welche Datenfelder erlaubt sind, welche Datentypen sie haben und, ob ein Knoten pro Subshop überschrieben werden darf oder nur einmalig existieren kann. Die Schemata beschreiben damit die Struktur der Konfigurationsdaten, nicht jedoch deren Inhalt. Die Konfiguration kann vollständig über die REST-API gepflegt werden. Das Admin Interface (AI) ist zusätzlich eine visuelle Darstellung dieser Schnittstelle. Alle Funktionen, die im Interface ausgeführt werden können, stehen auch über die API zur Verfügung – etwa das Erstellen, Anpassen, Löschen oder Überschreiben von Konfigurationsknoten. Damit eignet sich die API besonders für eine automatisierte Verwaltung der Konfiguration, etwa im Rahmen von: * CI/CD-Prozessen mit klar definierten Konfigurationszuständen, * dem Abgleich von Einstellungen zwischen Test- und Produktivsystemen, * oder der Verwaltung mandantenfähiger Umgebungen mit subshop-spezifischen Varianten. Die REST-API bietet somit vollständigen Zugriff auf die Konfiguration ihres Shops. Um die Felder eines Knotens zu ermitteln, muss das zugehörige Schema über den Endpunkt `GET config/schemas/{type}` geladen werden. Die Struktur dieser Schemata wird im Feld `properties` beschrieben. Dort sind unter anderem die Felder `id`, `type` und optional `subtype` (z. B. bei `type: list`) enthalten. `id` legt fest, wie das Feld heißt, während `type` und `subtype` angeben, welche Inhalte erwartet werden. `type: object` kennzeichnet eine verschachtelte Struktur. Welche Konfigurationstypen im System verfügbar sind, lässt sich auf zwei Wegen abfragen: * über `GET config/nodeTypes`, das eine kompakte Liste aller Typen liefert, * oder alternativ über `GET config/schemas`, wo zusätzlich das Feld `id` enthalten ist. ### Gültige `{type}`- und `{selector}`-Werte Die folgenden Tabellen listen die gültigen Werte auf, die bei * `GET /api/config/schemas/{type}` als `{type}` und * `GET /api/config/nodes/{selector}` als **Top-Level-**`{selector}` verwendet werden können. Die Unterknoten, Parameter und Beispiele der einzelnen Bereiche sind nicht Teil dieser API-Referenz. Sie sind vollständig im Dokument [Konfiguration](/konfiguration) beschrieben. Dieser Abschnitt dient ausschließlich als Orientierungs für die gültigen Bezeichner. | **Typ / Selector** | **Kurzbeschreibung** | | -------------------- | ------------------------------------------------------------------------------------------------------------------------ | | `accounts` | → [accounts - Benutzerkonten](/konfiguration/accounts-benutzerkonten) | | `actions` | → [actions - Fehlertexte & E-Mails](/konfiguration/actions-fehlertexte-e-mails) | | `app` | → [app - WEBSALE APP](/konfiguration/app-websale-app) | | `authentication` | → [authentication - Authentifizierungs- & Zugriffsdaten](/konfiguration/authentication-authentifizierungs-zugriffsdaten) | | `b2b` | → [b2b - Business-to-Business (B2B)](/konfiguration/b2b-business-to-business-b2b) | | `basket` | → [basket - Warenkorb](/konfiguration/basket-warenkorb) | | `checkout` | → [checkout - Bestellablauf](/konfiguration/checkout-bestellablauf) | | `content` | → [content - Katalog (Kategorien & Produkte)](/konfiguration/content-katalog-kategorien-produkte) | | `creditCheck` | → [creditCheck - Bonitätsprüfung(old)](/konfiguration/creditcheck-bonitatsprufung) | | `customer` | → [customer - Kundendaten](/konfiguration/customer-kundendaten) | | `finance` | → [finance - Währungen & Steuern](/konfiguration/finance-wahrungen-steuern) | | `general` | → [general - Allgemeine Shopeinstellungen](/konfiguration/general-allgemeine-shopeinstellungen) | | `inquiry` | → [inquiry - Formulare](/konfiguration/inquiry-formulare) | | `maintenance` | → [maintenance - Wartungsmodus](/konfiguration/maintenance-wartungsmodus) | | `messages` | → [messages - Ereignisgesteuerte E-Mails](/konfiguration/messages-ereignisgesteuerte-e-mails) | | `newsletter` | → [newsletter - Newsletter](/konfiguration/newsletter-newsletter) | | `payment` | → [payment - Zahlungsarten](/konfiguration/payment-zahlungsmethoden) | | `search` | → [search - Suche (Core)](/konfiguration/search-sortierung-und-filterung) | | `security` | → [security - Sicherheit](/konfiguration/security-sicherheitsregeln) | | `seoMetaData` | → [seoMetaData - Meta-Daten & Seo-Texte](/konfiguration/seometadata-meta-daten-seo-texte) | | `shopSystemServices` | → [shopSystemServices - Zusatzmodule](/frontend/referenz/module) | | `urls` | → [urls - URL (Webadressen)](/konfiguration/urls-url-webadressen) | ## Methoden für Einstellungen Dieser Abschnitt beschreibt die verfügbaren REST-Endpunkte zur Verwaltung der Shop-Konfiguration im Admin-Bereich. Über die Schnittstelle können Schemas abgerufen, Konfigurationsknoten analysiert, geprüft, gelöscht oder vollständig zurückgesetzt werden. Die Konfiguration ist dabei in sogenannte Schemas und Knoten unterteilt, die verschiedenen Bereichen wie Accounts, Aktionen oder Systemfunktionen zugeordnet sind. Alle Einstellungen gelten entweder global oder subshopspezifisch und können je nach Schema typabhängig angepasst werden. Die Nutzung der Methoden setzt entsprechende Lese-, Schreib- oder Löschrechte voraus. ### GET config/setup Mit diesem Endpunkt wird die Setup-Konfiguration pro Subshop und Stage (z. B. `work`, `active`) abgerufen. Die Rückgabe enthält technische Informationen wie die `host`-, `staticDomain`- und `contentDomain`-Werte, die zur Laufzeitkonfiguration und Auslieferung der Inhalte im jeweiligen Subshop benötigt werden. Dieser Endpunkt dient primär der systeminternen oder administrativen Analyse des aktuellen Shop-Setups. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/config/setup ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "contentDomain": "content.myshop.localhost", "host": "myshop.localhost", "id": "deutsch", "stage": "work", "staticDomain": "static.myshop.localhost", "staticUrl": "/static" }, { "contentDomain": "content.myshop.localhost", "host": "myshop.localhost", "id": "deutsch", "stage": "active", "staticDomain": "static.myshop.localhost", "staticUrl": "/static" }, { "contentDomain": "content.myshop.localhost", "host": "english.localhost", "id": "english", "stage": "work", "staticDomain": "static.myshop.localhost", "staticUrl": "/static" }, { "contentDomain": "content.myshop.localhost", "host": "english.localhost", "id": "english", "stage": "active", "staticDomain": "static.myshop.localhost", "staticUrl": "/static" } ] ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | -------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte. | ### GET config/status Dieser Endpunkt prüft die Konfigurationsdaten auf Unvollständigkeit und Redundanz. Er meldet, ob Pflichtfelder fehlen oder Knoten mit identischen Daten mehrfach vorhanden sind.\ Wird kein Problem erkannt, wird `"status": "ok"` zurückgegeben. Die Nutzung erfordert Leseberechtigung für Konfigurationen. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/config/status ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "status": "ok" } ``` #### Antwort bei Fehlern Wenn Fehler erkannt werden, enthält die Antwort zusätzlich Details zu den gefundenen Problemen: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "status": "errors", "nonUniqueFields": [ { "id": "general.salutation.1", "type": "general.salutation", "field": "code" } ], "missingRequiredFields": { "general.salutation.1": [ "codeList" ] } } ``` Die Felder `nonUniqueFields` und `missingRequiredFields` erscheinen nur, wenn entsprechende Probleme erkannt werden. #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Konfigurationen. | ### GET config/schemas Dieser Endpunkt liefert eine vollständige Liste aller verfügbaren Konfigurationsschemata im System. Ein Schema beschreibt die Struktur und Eigenschaften eines bestimmten Konfigurationstyps, darunter z. B. Pflichtfelder, Datentypen, Schreibschutz, Überschreibbarkeit pro Subshop oder Singleton-Status. Die Schemata dienen als technische Grundlage für die Validierung und Bearbeitung von Konfigurationsdaten im Admin Interface oder in automatisierten Prozessen. Die Nutzung erfordert Leseberechtigungen für Konfigurationsdaten. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/config/schemas ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "id": "accounts.account", "schema": { "group": "accounts", "isCreatable": false, "isDeletable": false, "isMainNode": true, "isSingleton": true, "isSubshopOverwriteable": true, "properties": [ { "id": "login", "isOptional": false, "isReadOnly": false, "isUnique": false, "properties": [ { "default": 5, "id": "loginBlockCount", "isOptional": false, "isReadOnly": false, "isUnique": false, "type": "uint" }, { "default": 180, "id": "loginBlockDuration", "isOptional": false, "isReadOnly": false, "isUnique": false, "type": "uint" }, { "id": "loginBlockEmail", "isOptional": false, "isReadOnly": false, "isUnique": false, "properties": [ { "id": "template", "isOptional": false, "isReadOnly": false, "isUnique": false, "type": "string" }, { "id": "subject", "isOptional": false, "isReadOnly": false, "isUnique": false, "type": "string" }, ... ], "type": "object" }, { "default": false, "id": "ipBlockEnabled", "isOptional": false, "isReadOnly": false, "isUnique": false, "type": "bool" }, { "default": 10, "id": "ipBlockCount", "isOptional": false, "isReadOnly": false, "isUnique": false, "type": "uint" }, { "default": 1, "id": "ipBlockCountDuration", "isOptional": false, "isReadOnly": false, "isUnique": false, "type": "uint" }, { "default": 10, "id": "ipBlockDuration", "isOptional": false, "isReadOnly": false, "isUnique": false, "type": "uint" } ], "type": "object" }, { "id": "passwordChecks", "isOptional": false, "isReadOnly": false, "isUnique": false, "type": "multiService" }, ... ], "type": "account" }, "type": "account", "updatedAt": "2025-04-28T10:24:13.000Z" }, ... ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Konfigurationen. | ### GET config/schemas/\{type} Mit diesem Endpunkt kann das Schema eines bestimmten Konfigurationstyps abgerufen werden. Das Schema definiert die zulässigen Felder, deren Datentypen, optionale und Pflichtangaben sowie administrative Eigenschaften wie Schreibschutz, Löschbarkeit oder Subshop-Überschreibbarkeit. Die Informationen dienen dem Admin Interface und anderen Tools zur strukturellen Validierung und Darstellung von Konfigurationseinträgen im System. Leserechte für Konfigurationsdaten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/config/schemas/general.salutation ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "group": "general", "isCreatable": false, "isDeletable": false, "isMainNode": true, "isSingleton": true, "isSubshopOverwriteable": true, "properties": [ { "id": "codeList", "isOptional": false, "isReadOnly": false, "isUnique": false, "properties": [ { "id": "code", "isOptional": false, "isReadOnly": false, "isUnique": false, "type": "string" }, { "id": "text", "isOptional": false, "isReadOnly": false, "isUnique": false, "type": "string" } ], "subtype": "object", "type": "list" } ], "type": "salutation" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Konfigurationen. | | 404 Not Found | "schema not found" | Das Schema wurde nicht gefunden. | ### GET config/schemas/\{type}/defaults Mit diesem Endpunkt können Standardparameter einer Konfiguration abgerufen werden. Die Antwort enthält eine vollständige Vorlage für den angegebenen Konfigurationstyp. Leserechte für Konfigurationsdaten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/config/schemas/content.imageFormat/defaults ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "data": { "autoConvert": { "active": false, "allowExternalTrigger": false, "hour": [ ], "sourceDirectory": "", "weekday": [ ] }, "check": { "dpi": { "active": false, "max": 0, "min": 0 }, "fileSize": { "active": false, "max": 0.0, "maxUnit": "byte", "min": 0.0, "minUnit": "byte" }, "inputTypeRestriction": { "active": false, "allowedTypes": [ ] } }, "convert": { "additionalArguments": "", "changeType": { "active": false, "type": "jpg" }, "quality": { "active": false, "value": 100 }, "removeMetadata": false, "resize": { "active": false, "background": "#FFFFFF", "height": 0, "orientation": "center", "type": "scale", "width": 0 }, "sharpen": { "active": false, "sigma": 1.0 } }, "description": "", "name": "", "output": { "handleIfExists": "overwrite", "nameSuffix": "", "targetDirectory": "" }, "type": "product" }, "id": "content.imageFormat", "label": "imageFormat", "type": "imageFormat" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Konfigurationen. | | 404 Not Found | "schema not found" | Das Schema wurde nicht gefunden. | ### GET config/nodeTypes Dieser Endpunkt liefert eine Übersicht über alle im System vorhandenen **Konfigurationsknotentypen**, gruppiert nach Schema. Für jeden Typ wird die Anzahl der erfassten Knoten zurückgegeben – also wie viele Konfigurationseinträge zu einem bestimmten Typ aktuell existieren. Die Information eignet sich beispielsweise zur Bestandsaufnahme, zur Validierung der Konfigurationsstruktur oder als Grundlage für die dynamische Darstellung im Admin Interface. Zum Abruf sind Leseberechtigungen für Konfigurationen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/config/nodeTypes ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "count": 1, "type": "accounts.account" }, { "count": 1, "type": "accounts.accountRestrictions" }, { "count": 1, "type": "accounts.addressField" }, { "count": 0, "type": "accounts.addressFieldsSettings" }, { "count": 0, "type": "accounts.bankInfoField" }, { "count": 0, "type": "accounts.creditCardField" }, { "count": 0, "type": "accounts.customAddressField" }, { "count": 1, "type": "actions.accountDelete" }, { "count": 1, "type": "actions.accountRegister" }, { "count": 1, "type": "actions.addressCreate" }, { "count": 1, "type": "actions.addressDelete" }, { "count": 1, "type": "actions.addressUpdate" }, { "count": 1, "type": "actions.basketItemAdd" }, { "count": 1, "type": "actions.basketItemDelete" }, ... ] ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Konfigurationen. | ## Methoden für die Verwaltung von Knoten im Shop Über diese Methoden können Konfigurationsknoten im Shop ausgelesen, erstellt, aktualisiert oder gelöscht werden. Dabei handelt es sich um konkrete Instanzen von Einstellungen, die im Admin-Bereich des Shops gepflegt werden – z. B. für das Verhalten beim Account-Login oder für Einwilligungsdienste wie Cookie-Services. Je nach Typ des zugrunde liegenden Schemas kann ein Konfigurationsknoten entweder: * als Singleton definiert sein – d. h. es darf nur ein einziger Knoten dieses Typs im Shop existieren (z. B. ein globaler Login-Knoten), * oder als Multiknoten – bei dem mehrere Knoten desselben Typs erlaubt sind (z. B. mehrere Cookie-Services unter `general.consentCookieService`). Die Gültigkeit der Daten wird beim Anlegen oder Aktualisieren anhand des zugehörigen Schemas geprüft. Die Zugriffe setzen entsprechende Berechtigungen zum Lesen, Schreiben oder Löschen von Konfigurationen voraus. ### GET config/nodes/\{selector} Mit dieser Methode wird die Konfiguration eines oder mehrerer Knoten basierend auf dem angegebenen `selector` geladen. Der `selector` setzt sich in der Regel aus dem Schema und dem Knotentyp zusammen (z. B. `actions.guestRegister` oder `general.consentCookieService`). Abhängig vom Knoten liefert der Endpunkt entweder ein einzelnes Konfigurationselement oder eine Liste von Elementen. Die Antwort enthält jeweils die Konfigurationsdaten sowie Metainformationen wie `id`, `type`, `label` und `updatedAt`. Die Lese-Berechtigung für Konfigurationsdaten ist erforderlich. #### Beispiel 1 ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/config/nodes/actions.guestRegister ``` #### Antwort 1 ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "data": { "errorCodes": { "createError": "Fehler beim Anlegen des Accounts", "duplicateEmail": "Für die E-Mail existiert bereits ein Account", "missingEmail": "E-Mail fehlt", "missingPassword": "Passwort fehlt", "nonGuestAccount": "Kein Gast-Account", "passwordCheckFailed": "Passwort ungenügend", "passwordMismatch": "Passwörter stimmen nicht überein" }, "restrictions": { "autoLoginAllowed": true }, "verifyEmail": { "fromAddress": "noreply@websale.de", "fromName": "Mein Onlineshop", "subject": "Mein Onlineshop | Registrierung", "template": "accountRegister.htm" } }, "id": "actions.guestRegister", "label": "guestRegister", "type": "guestRegister", "updatedAt": "2025-02-17T14:24:08.000Z" } ] } ``` #### Beispiel 2 ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/config/nodes/general.consentCookieService ``` #### Antwort 2 ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "data": { "description": "", "label": "Google Analytics", "name": "google", "service": { "externalService": {}, "shopService": null } }, "id": "general.consentCookieService.googleAnalytics", "label": "consentCookieService", "type": "consentCookieService", "updatedAt": "2025-02-17T14:24:18.000Z" }, ... ], "nextPageToken": "MA", "totalCount": 21 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Konfigurationen. | | 400 Bad Request | "invalidSelector" | `{selector}` hat mehr als 3 Teile, die durch einen `.` getrennt sind.
    Die Konfiguration wurde nicht gefunden. | | 400 Bad Request | "invalidParams" | Der Query-Parameter `sort` ist ungültig. Die Antwort enthält ein `errorContext`-Objekt mit Details (z. B. `{"sort": {"type": "invalidValue"}}`). Gültiges Format: `{feld}:{richtung}` mit `feld` = `id` oder `updatedAt` und `richtung` = `asc` oder `desc`. | ### PUT config/nodes/\{selector} Diese Methode dient zum Aktualisieren eines Konfigurationsknotens anhand seines Selectors. Der übergebene Dateninhalt wird dabei automatisch gegen das hinterlegte Schema geprüft. Wird das Schema verletzt, erfolgt eine detaillierte Fehlermeldung. Der Selector besteht aus zwei oder drei durch Punkte getrennten Teilen (z. B. `actions.guestRegister` oder `general.consentCookieService.googleAnalytics`). Das Format muss korrekt sein, damit die Konfiguration eindeutig zugeordnet werden kann. Wenn die Validierung fehlgeschlagen ist, enthält die Antwort Hinweise in Textform im Feld `detail`. Zum Beispiel: “The value of the field 'name' has the wrong type. Expected: string.”. Fehler sind auch im Feld `errorContext` aufgelistet. Mögliche Fehlertypen (`errorContext.{field}.type`): `WrongType`\ `WrongEnumValue`\ `KeyNotAllowed`\ `IsReadOnly`\ `NotUnique`\ `InvalidSelfAssociation`\ `ServiceNotFound`\ `AssociationWrongType`\ `ServiceMissing`\ `AssociationNotFound`\ `ServiceWrongType`\ `TextMissing` Schreibberechtigungen für Konfigurationen sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/config/nodes/actions.guestRegister ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "data": { "errorCodes": { "createError": "Fehler beim Anlegen des Accounts", "duplicateEmail": "Für die E-Mail existiert bereits ein Account", "missingEmail": "E-Mail fehlt", "missingPassword": "Passwort fehlt", "nonGuestAccount": "Kein Gast-Account", "passwordCheckFailed": "Passwort ungenügend", "passwordMismatch": "Passwörter stimmen nicht überein" }, "restrictions": { "autoLoginAllowed": true }, "verifyEmail": { "fromAddress": "noreply@websale.de", "fromName": "Mein Onlineshop", "subject": "Mein Onlineshop | Registrierung", "template": "accountRegister.htm" } } } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "data": { }, "id": "actions.guestRegister", "label": "guestRegister", "type": "guestRegister", "updatedAt": "2025-02-17T14:24:08.000Z" } ``` #### Antwort wenn die Validierung Fehlgeschlagen ist ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "detail": "The value of the field 'name' has the wrong type. Expected: string. The value of the field 'service.externalService' has the wrong type. Expected: object.", "error": "dataNotCorrect", "errorContext": { "name": { "type": "WrongType", "expectedType": "string" }, "service.externalService": { "type": "WrongType", "expectedType": "object" } } } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Konfigurationen.
    Es wird versucht, eine Konfiguration zu aktualisieren, die Websale AG gehört. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidSelector" | `{selector}` hat nicht 2 und nicht 3 Teile, die durch einen `.` getrennt sind. | | 400 Bad Request | "invalidParams" | Pflichtfelder fehlen oder haben den falschen Typ. Die Antwort enthält ein `errorContext`-Objekt mit Details zu den betroffenen Feldern (z. B. `{"data": {"type": "missing", "expectedType": "object"}}`). | | 400 Bad Request | "dataNotCorrect" | Daten entsprechen dem Schema nicht. Es wird ein Kommentar geliefert, wo steht, was genau nicht stimmt. | | 409 Conflict | "alreadyExists" | Der Knoten existiert bereits (z. B. bei gleichzeitiger Erstellung eines Singleton-Knotens). | | 400 Bad Request | "updateFailed" | Das Aktualisieren ist fehlgeschlagen. | | 404 Not Found | "NodeNotFound" | Die Konfiguration wurde nicht gefunden. | | 503 Service Unavailable | "internalError" | Sonstiger Fehler. Details sind in Logs zu finden. | ### POST config/nodes/\{selector} Ein Konfigurationsknoten wird erstellt, dabei wird die Schema-Gültigkeit geprüft. Diese Methode legt einen neuen Konfigurationsknoten innerhalb des angegebenen Schemas an. Dabei wird geprüft, ob der Knoten gemäß Schema erstellt werden darf (z. B. nicht bei Singleton-Schemata) und ob die übergebenen Daten gültig sind. Die Struktur muss dem Schema entsprechen, sonst wird der Vorgang mit einer präzisen Fehlermeldung abgelehnt. Der `selector` besteht immer aus zwei durch Punkt getrennten Teilen (z. B. `general.consentCookieService`), die den Schema-Typ beschreiben. Zusätzlich muss im Request-Body ein eindeutiges `id`-Feld angegeben werden, das an den Selector angehängt wird (z. B. `test` → ergibt `general.consentCookieService.test`). Wenn die Validierung fehlgeschlagen ist, enthält die Antwort Hinweise in Textform im Feld `detail`. Zum Beispiel: “The value of the field 'name' has the wrong type. Expected: string.”. Fehler sind auch im Feld `errorContext` aufgelistet. Mögliche Fehlertypen (`errorContext.{field}.type`): `WrongType`\ `WrongEnumValue`\ `KeyNotAllowed`\ `IsReadOnly`\ `NotUnique`\ `InvalidSelfAssociation`\ `ServiceNotFound`\ `AssociationWrongType`\ `ServiceMissing`\ `AssociationNotFound`\ `ServiceWrongType`\ `TextMissing` Erstellrechte für Konfigurationen sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/config/nodes/general.consentCookieService ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "data": { "description": "", "label": "Econda Analytics", "name": "econda", "service": { "externalService": {}, "shopService": null } }, "id": "test" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "data": { "description": "", "label": "Econda Analytics", "name": "econda", "service": { "externalService": {}, "shopService": null } }, "id": "general.consentCookieService.test", "label": "consentCookieService", "type": "consentCookieService" } ``` #### Antwort wenn die Validierung Fehlgeschlagen ist ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "detail": "The value of the field 'name' has the wrong type. Expected: string. The value of the field 'service.externalService' has the wrong type. Expected: object.", "error": "dataNotCorrect", "errorContext": { "name": { "type": "WrongType", "expectedType": "string" }, "service.externalService": { "type": "WrongType", "expectedType": "object" } } } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Konfigurationen. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidSelector" | `{selector}` hat nicht 2 Teile, die durch einen `.` getrennt sind. | | 400 Bad Request | "typeInvalid" | Es gibt kein Schema mit dem Typ des Konfigurationsknotens. | | 400 Bad Request | "creationDenied" | Das Schema ist ein `singleton`.
    Das Schema hat die Eigenschaft `creatable: false`. | | 400 Bad Request | "invalidParams" | Pflichtfelder (`id`, `data`) fehlen, haben den falschen Typ oder sind leer. Die Antwort enthält ein `errorContext`-Objekt mit Details zu den betroffenen Feldern (z. B. `{"id": {"type": "missing", "expectedType": "string"}}` oder `{"id": {"type": "invalidValue"}}`). | | 400 Bad Request | "dataNotCorrect" | Daten entsprechen dem Schema nicht. Es wird ein Kommentar geliefert, wo steht, was genau nicht stimmt. | | 409 Conflict | "alreadyExists" | `id` wurde schon verwendet. | | 503 Service Unavailable | "internalError" | Sonstiger Fehler. Details sind in Logs zu finden. | ### DELETE config/nodes/\{selector} Diese Methode löscht einen bestehenden Konfigurationsknoten. Der angegebene `selector` muss genau drei durch Punkt getrennte Teile enthalten (z. B. `general.consentCookieService.google`). Vor dem Löschen wird geprüft, ob das zugehörige Schema dies erlaubt – etwa ob es sich nicht um ein Singleton handelt oder das Löschen explizit untersagt ist. Löschrechte für Konfigurationen sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/config/nodes/general.consentCookieService.google ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Konfigurationen.
    Es wird versucht, eine Konfiguration zu löschen, die Websale AG gehört. | | 400 Bad Request | "invalidSelector" | `{selector}` hat mehr bzw. weniger als 3 Teile, die durch einen `.` getrennt sind. | | 400 Bad Request | "idInvalid" | Die Konfiguration wurde nicht gefunden. | | 400 Bad Request | "typeInvalid" | Es gibt kein Schema mit dem Typ des Konfigurationsknotens. | | 400 Bad Request | "deletionDenied" | Das Schema ist ein `singleton`.
    Das Schema hat die Eigenschaft `deletable: false`. | | 400 Bad Request | "node not deleted" | Das Löschen ist fehlgeschlagen. | ### POST config/nodes/\{selector}/move Mit dieser Methode wird ein bestehender Konfigurationsknoten innerhalb seines Typs neu einsortiert. Verschoben wird ausschließlich innerhalb desselben Typs – ein Knoten kann also nur relativ zu anderen Knoten desselben Typs positioniert werden. Die neue Position wird über genau einen der beiden Zielparameter `beforeTarget` oder `afterTarget` festgelegt: * Mit `beforeTarget` wird der Knoten direkt **vor** dem angegebenen Zielknoten platziert. * Mit `afterTarget` wird der Knoten direkt **nach** dem angegebenen Zielknoten platziert. Es darf immer nur einer der beiden Parameter gesetzt sein. Werden beide oder keiner angegeben, wird der Vorgang abgelehnt. Schreibberechtigungen für Konfigurationen sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/config/nodes/general.consentCookieService.econda/move ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "beforeTarget": "general.consentCookieService.google" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | --------------- | ------------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte, um auf diese Konfiguration zuzugreifen. | | 400 Bad Request | "invalidParams" | `beforeTarget` und `afterTarget` wurden beide angegeben oder es wurde keiner der beiden Parameter angegeben. | | 400 Bad Request | "badSelector" | Die Konfiguration `{selector}` existiert nicht. | | 400 Bad Request | "idInvalid" | `beforeTarget`/`afterTarget` existieren nicht oder sind von einem anderen Typ als `{selector}`. | ## Methoden für die Verwaltung von Knoten in Subshops Die hier dokumentierten Endpunkte ermöglichen es, Konfigurationsknoten für einzelne Subshops gezielt zu überschreiben. Damit lassen sich abweichende Einstellungen je Subshop realisieren – etwa verschiedene Datenschutzdienste oder abweichende E-Mail-Konfigurationen. Die Methoden orientieren sich am allgemeinen Schema der Knotenverwaltung, erweitern es jedoch um die zusätzliche Angabe einer `subshopId`. ### GET config/nodes/\{selector}/overwrites Mit dieser Methode wird eine Liste aller Überschreibungen für einen bestimmten Konfigurationsknoten zurückgegeben. Dabei handelt es sich um Konfigurationen, die gezielt für einzelne Subshops angepasst wurden. Ist der Knoten nicht überschreibbar, wird ein leeres JSON-Array (`[]`) zurückgegeben. Liegen keine Überschreibungen vor, enthält das Ergebnis ein `items`-Objekt mit leerem Array. Leseberechtigungen für Konfigurationen sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/config/nodes/general.consentCookieService.econda/overwrites/ ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "data": { "description": "", "label": "", "name": "", "service": { "externalService": null, "shopService": null } }, "nodeId": "general.consentCookieService.econda", "subshopId": "deutsch" } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ----------------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Konfigurationen. | | 400 Bad Request | "invalidSelector" | `{selector}` hat nicht 2 und nicht 3 Teile, die durch einen `.` getrennt sind. | | 400 Bad Request | "typeInvalid" | Es gibt kein Schema mit dem Typ aus dem `{selector}`. | | 404 Not found | "nodeNotFound" | Die Konfiguration wurde nicht gefunden. | ### GET config/nodes/\{selector}/overwrites/\{subshopId} Diese Methode lädt die Subshop-spezifische Überschreibung eines bestimmten Konfigurationsknotens. Existiert keine Überschreibung für den angegebenen Subshop, wird ein entsprechender Fehler zurückgegeben. Ist der Knoten nicht überschreibbar, wird ein Fehler zurückgegeben (`inappropriateScheme`). Leseberechtigungen für Konfigurationen sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/config/nodes/security.recaptchav3/overwrites/deutsch/ ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "data": { "minimumScore": 0.0, "name": "", "secretKey": "", "verifyUrl": "" }, "nodeId": "security.recaptchav3", "subshopId": "deutsch" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ----------------------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Konfigurationen. | | 400 Bad Request | "invalidSelector" | `{selector}` hat nicht 2 und nicht 3 Teile, die durch einen `.` getrennt sind. | | 400 Bad Request | "typeInvalid" | Es gibt kein Schema mit dem Typ aus dem `{selector}`. | | 400 Bad Request | "inappropriateScheme" | Der Knoten ist nicht überschreibbar. | | 404 Not found | "nodeNotFound" | Die Konfiguration wurde nicht gefunden. | | 404 Not found | "nodeOverwriteNotFound" | Die Überschreibung wurde nicht gefunden. | ### PUT config/nodes/\{selector}/overwrites/\{subshopId} Mit dieser Methode kann ein Konfigurationsknoten für einen bestimmten Subshop überschrieben werden. Die Daten im Request Body müssen dem Schema des ursprünglichen Knotens entsprechen. Nur Knoten mit entsprechender Eigenschaft können überschrieben werden. Wenn die Validierung fehlgeschlagen ist, enthält die Antwort Hinweise in Textform. Zum Beispiel: “The value of the field 'name' has the wrong type. Expected: string.”. Fehler sind auch im Feld `errorContext` aufgelistet. Mögliche Fehlertypen (`errorContext..type`): `WrongType`\ `WrongEnumValue`\ `KeyNotAllowed`\ `IsReadOnly`\ `NotUnique`\ `InvalidSelfAssociation`\ `ServiceNotFound`\ `AssociationWrongType`\ `ServiceMissing`\ `AssociationNotFound`\ `ServiceWrongType`\ `TextMissing` Erstellberechtigungen für Konfigurationen sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/config/nodes/general.consentCookieService/overwrites/english ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "data": { "description": "", "label": "Econda Analytics", "name": "econda", "service": { "externalService": {}, "shopService": null } } } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "data": { "description": "", "label": "Econda Analytics", "name": "econda", "service": { "externalService": {}, "shopService": null } }, "nodeId": "general.consentCookieService", "subshopId": "english" } ``` #### Antwort wenn die Validierung Fehlgeschlagen ist ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "detail": "The value of the field 'name' has the wrong type. Expected: string. The value of the field 'service.externalService' has the wrong type. Expected: object.", "error": "dataNotCorrect", "errorContext": { "name": { "type": "WrongType", "expectedType": "string" }, "service.externalService": { "type": "WrongType", "expectedType": "object" } } } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Konfigurationen.
    Es wird versucht, eine Konfiguration zu aktualisieren, die Websale AG gehört. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidSubshopId" | Subshop wurde nicht gefunden. | | 400 Bad Request | "invalidSelector" | `{selector}` hat nicht 2 und nicht 3 Teile, die durch einen `.` getrennt sind. | | 400 Bad Request | "typeInvalid" | Es gibt kein Schema mit dem Typ aus dem `{selector}`. | | 400 Bad Request | "overwriteDenied" | Der Knoten darf nicht überschrieben werden. | | 400 Bad Request | "invalidParams" | `data` fehlt oder hat einen falschen Typ. Die Antwort enthält ein `errorContext`-Objekt mit Details. | | 400 Bad Request | "dataNotCorrect" | Daten entsprechen dem Schema nicht. Es wird ein Kommentar geliefert, wo steht, was genau nicht stimmt. | | 409 Conflict | "alreadyExists" | Konflikt: Die Überschreibung existiert bereits. | | 404 Not Found | "NodeNotFound" | Der Knoten, der überschrieben werden soll, wurde nicht gefunden. | | 503 Service Unavailable | "internalError" | Sonstiger Fehler. Details sind in Logs zu finden. | ### DELETE config/nodes/\{selector}/overwrites/\{subshopId} Diese Methode entfernt die vorhandene Überschreibung eines Konfigurationsknotens für einen bestimmten Subshop. Wird keine gültige Überschreibung gefunden oder ist das Löschen nicht erlaubt, erfolgt eine entsprechende Fehlermeldung. Löschberechtigungen für Konfigurationen sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/config/nodes/general.consentCookieService/overwrites/english ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Konfigurationen.
    Es wird versucht, eine Konfiguration zu löschen, die Websale AG gehört. | | 400 Bad Request | "invalidSelector" | `{selector}` hat nicht 2 und nicht 3 Teile, die durch einen `.` getrennt sind. | | 400 Bad Request | "typeInvalid" | Es gibt kein Schema mit dem Typ aus dem `{selector}`. | | 400 Bad Request | "subshopIdMissing" | `subshopId` wurde nicht übergeben. | | 400 Bad Request | "unknownOverwriting" | Das Löschen ist fehlgeschlagen. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Kundendaten Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-kundendaten Kundenkonten, Adressen und Bankverbindungen über die Admin Interface API anlegen, abrufen, aktualisieren, löschen und exportieren. Der Endpunkt `customerAccounts/` stellt eine REST-Schnittstelle zur Verfügung, über die Kundendaten im Shop-System verwaltet werden können. Die API ermöglicht das Erstellen, Abrufen, Aktualisieren und Löschen von Kundenkonten, Adressen und Bankverbindungen. Zusätzlich lassen sich Daten exportieren oder Passwortrücksetzungen initiieren. Alle Endpunkte sind so gestaltet, dass sie eine systematische Verwaltung und Pflege von Kundendaten über das Admin-Interface hinaus ermöglichen. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | ----------------- | ---------------------------- | --------------------- | --------------------- | --------------------- | --------------------- | | **Kundendaten** | customerAccounts/ | | | | | | **Adressen** | customerAccounts/…/addresses | | | | | | **Bankdaten** | customerAccounts/…/bankData | | | | | | **Bulk-Abfragen** | bulk/ | | | | | ## Datenfelder ### Datenfelder eines Kundenkontos | **Name** | **Typ** | **Bedeutung** | | ------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **allSubshopsAllowed** | Boolean | Gibt an, ob der Kunde für alle Subshops freigeschaltet ist | | **allowedSubshopIds** | String\[] | Liste der Subshops, für die der Kunde freigeschaltet ist | | **blockedPaymentMethods** | String\[] | Liste von Zahlarten-Filtern, die für dieses Konto gesperrt sind. Gesperrte Zahlarten stehen weder dem Konto selbst noch dessen Mitarbeiterkonten zur Verfügung.
    Jeder Eintrag kann die Wildcard `*` enthalten, ein vorangestelltes `!` negiert das Muster (z. B. `["*", "!invoice"]` = alle Zahlarten außer `invoice` sperren) | | **createdAt** | String | Zeitpunkt der Kontoerstellung (ISO 8601-Format, UTC) | | **customerNumber** | String | Vom System oder extern vergebene Kundennummer | | **deleted** | Boolean | Gibt an, ob das Konto gelöscht wurde | | **displayName** | String | Anzeigename des Kunden (wird z. B. bei Kommentaren oder Bewertungen angezeigt) | | **email** | String | E-Mail-Adresse des Kunden | | **enabledPaymentMethods** | String\[] | Liste von Zahlarten-Filtern, die für dieses Konto gezielt freigeschaltet sind. Relevant für Zahlarten, die in der Konfiguration mit `availableByDefault: false` angelegt wurden und damit nicht standardmäßig verfügbar sind (siehe [Konfiguration Zahlungsmethoden](/konfiguration/payment-zahlungsmethoden)).
    Wildcard `*` und Negation per `!` werden wie bei `blockedPaymentMethods` unterstützt | | **id** | Integer | Interne eindeutige ID des Kunden | | **loginBlocked** | Boolean | Gibt an, ob der Login für dieses Konto gesperrt ist | | **mainSubshop** | String | Haupt-Subshop | | **meta.currentLogin** | String | Zeitpunkt des aktuellen Logins (ISO 8601-Format, UTC) | | **meta.dataSets.accountBasketId** | String | Das zugeordnete Warenkorb-ID des Kundenkontos | | **meta.dataSets.lastUsedBillAddressId** | Integer | ID der zuletzt genutzten Rechnungsadresse | | **meta.dataSets.lastUsedDeliveryAddressId** | Integer | ID der zuletzt genutzten Lieferadresse | | **meta.dataSets.lastUsedPaymentMethodId** | String | ID der zuletzt verwendeten Zahlungsart | | **meta.dataSets.lastUsedPseudoCCId** | String | ID, anhand der Kreditkartendaten zum letzten Mal gefunden wurden | | **meta.dataSets.lastUsedShippingMethodId** | String | ID der zuletzt genutzten Versandart | | **meta.dataSets.mainAddressId** | Integer | ID der Hauptadresse des Kunden | | **meta.emailVerificationState** | Integer | Verifizierungsstatus der E-Mail-Adresse
    Mögliche Werte:
    `0` = Unbekannt
    `1` = Verifiziert durch Double-Opt-In
    `2` = Nicht verifiziert | | **meta.firstLogin** | String | Zeitpunkt des ersten Logins (ISO 8601-Format, UTC) | | **meta.lastChangedAt** | String | Zeitpunkt der letzten Änderung am Konto | | **meta.lastChangedBy** | String | Quelle der letzten Änderung (z. B. „shop“, "admin") | | **meta.lastInvitedBy** | Integer | ID des Administrators, der zuletzt einen Einladungslink oder einen Passwort-Reset-Link an den Benutzer gesendet hat. | | **meta.lastLogin** | String | Zeitpunkt des letzten Logins (ISO 8601-Format, UTC) | | **meta.lastTimeAskedForPasswordReset** | String | Zeitpunkt, zu dem zuletzt ein Passwort-Reset-Link angefordert wurde (ISO 8601-Format, UTC) | | **meta.lastTimeInvitationLinkClicked** | String | Zeutpunkt, zu dem der Einladungslink zuletzt angeklickt wurde (ISO 8601-Format, UTC) | | **meta.lastTimeInvitationLinkSent** | String | Zeitpunkt, zu dem der Einladungslink zuletzt versendet wurde (ISO 8601-Format, UTC) | | **moneySpent** | Float | Bisher ausgegebene Summe des Kontos, die auf die Budgetgrenze `paymentLimit` angerechnet wird | | **passwordResetRequired** | Boolean | Gibt an, ob der Kunde beim nächsten Login sein Passwort ändern muss | | **paymentLimit** | Integer | Globale Budgetgrenze des Kontos über alle Bestellungen (`0` = keine Grenze) | | **paymentLimitPerOrder** | Integer | Maximaler Bestellwert pro Bestellung (`0` = keine Grenze) | | **phone** | String | Telefonnummer des Kunden | | **meta.invitationStatus** | String | Status der Konto-Einladung. Mögliche Werte: `notSent`, `sent`, `expired`, `clicked` | | **meta.invitationLinkValidUntil** | String | Gültigkeit des Einladungslinks (ISO 8601 Zeitstempel, leer wenn nicht gesetzt) | | **meta.passwordLinkValidUntil** | String | Gültigkeit des Passwort-Reset-Links (ISO 8601 Zeitstempel, leer wenn nicht gesetzt) | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "addresses": [ { "additionalInfo": "", "addressType": "1", "businessFax": "", "businessPhone": "", "city": "asdf", "company": "WEBSALE AG", ... } ], "allSubshopsAllowed": false, "allowedSubshopIds": [ "deutsch" ], "bankData": [ { "accountNumber": "", "bankCode": "", "bankName": "myBank", "bic": "INGDDEFFXXX", "custom": null, "iban": "DE746374637463746300", ... } ], "createdAt": "2024-09-03T10:09:34.000Z", "customerNumber": "", "deleted": false, "displayName": "", "email": "root@root.root", "id": 1, "loginBlocked": false, "mainSubshop": "", "meta": { "currentLogin": "2025.04.16-12:12:04.899", "dataSets": { "accountBasketId": "", "lastUsedBillAddressId": 108, "lastUsedDeliveryAddressId": 108, "lastUsedPaymentMethodId": "safepayment", "lastUsedPseudoCCId": "", "lastUsedShippingMethodId": "hermes", "mainAddressId": 108 }, "emailVerificationState": 0, "invitationLinkValidUntil": "", "invitationStatus": "notSent", "lastChangedAt": "1970.01.01-00:00:00.000", "lastChangedBy": "shop", "lastLogin": "2025.04.16-08:12:31.895", "passwordLinkValidUntil": "" }, "passwordResetRequired": false, "phone": "" } ``` ### Datenfelder einer Adresse | **Name** | **Typ** | **Bedeutung** | | ------------------ | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **additionalInfo** | String | Zusätzliche Adressinformationen (z. B. Etage, Hausname etc.) | | **addressType** | String | Unbekannt (`"0"`), Rechnungs- und Lieferadresse (`"1"`), Rechnungsadresse (`"2"`), Lieferadresse (`"3"`) | | **businessFax** | String | Geschäftsfax | | **businessPhone** | String | Geschäftstelefon | | **city** | String | Stadt | | **company** | String | Firmenname (sofern vorhanden) | | **country** | String | Ländercode (Eingabe als ISO 3166-1 alpha-2/alpha-3/numerisch, z. B. "DE"). In GET-Responses wird das Feld als Objekt zurückgegeben mit den Feldern: `isoAlpha2`, `isoAlpha3`, `isoNum`, `name` | | **custom** | Objekt | Benutzerdefinierte Felder | | **dateOfBirth** | String | Geburtsdatum | | **department** | String | Abteilung | | **fax** | String | Faxnummer | | **firstName** | String | Vorname | | **id** | Integer | Eindeutige ID der Adresse | | **lastName** | String | Nachname | | **mobilePhone** | String | Mobilnummer | | **phone** | String | Telefonnummer | | **salutationCode** | String | Anrede-Code (z. B. "1" für "Herr", "2" für "Frau") | | **state** | String | Bundesland / Region | | **street** | String | Straßenname | | **streetNumber** | String | Hausnummer | | **taxId** | String | Mehrwertsteuer-ID | | **titleCode** | String | Titel-Code (z. B. "2" für "Dr.") | | **zip** | String | Postleitzahl | | **externalId** | String | Externe ID für die Adresse (optional) | | **labels** | String\[] | Liste von Labels/Tags für die Adresse (optional) | | **updatedAt** | String | Zeitstempel der letzten Änderung (ISO 8601, nur in Listen-Responses enthalten) | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "additionalInfo": "", "addressType": "1", "businessFax": "", "businessPhone": "", "city": "asdf", "company": "WEBSALE AG", "country": "DE", "custom": null, "dateOfBirth": "14.07.1967", "department": "", "externalId": "", "fax": "", "firstName": "asdff", "id": 5, "labels": [], "lastName": "asdf", "mobilePhone": "", "phone": "+49123456789", "salutationCode": "1", "state": "", "street": "asdf", "streetNumber": "9", "taxId": "", "titleCode": "2", "zip": "99999" } ``` ### Datenfelder eines Bankkontos | **Name** | **Typ** | **Bedeutung** | | -------------------------- | --------- | ------------------------------------------------------------------------------ | | **accountNumber** | String | ID des Zahlungskontos (veraltet, meist durch IBAN ersetzt) | | **bankCode** | String | Bankleitzahl (BLZ) des Kreditinstituts | | **bankName** | String | Name der Bank | | **bic** | String | BIC (Business Identifier Code) der Bank für internationale Zahlungen | | **custom** | Objekt | Benutzerdefinierte Felder | | **iban** | String | IBAN (Internationale Bankkontonummer) des Zahlungskontos | | **id** | Integer | Eindeutige ID des Bankdatensatzes | | **owner** | String | Name des Kontoinhabers | | **sepaDebitType** | String | Typ des SEPA-Lastschriftverfahrens (z. B. "CORE", "B2B") | | **sepaDirectDebitMandate** | String | Mandatsreferenznummer für SEPA-Lastschrift | | **sepaMandateDate** | String | Datum der Mandatserteilung (z. B. 2025-01-01) | | **sepaMandateType** | String | Art des SEPA-Mandats (z. B. "Erstmandat", "Folgemandat") | | **externalId** | String | Externe ID für die Bankverbindung (optional) | | **labels** | String\[] | Liste von Labels/Tags für die Bankverbindung (optional) | | **updatedAt** | String | Zeitstempel der letzten Änderung (ISO 8601, nur in Listen-Responses enthalten) | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountNumber": "", "bankCode": "", "bankName": "myBank", "bic": "INGDDEFFXXX", "custom": null, "externalId": "", "iban": "DE746374637463746300", "id": 1778681, "labels": [], "owner": "Max Mustermann", "sepaDebitType": "", "sepaDirectDebitMandate": "", "sepaMandateDate": "", "sepaMandateType": "" } ``` ## Methoden für Kundendaten Die hier beschriebenen Methoden ermöglichen das vollständige Verwalten von Kundendaten im System. Dazu zählen das Abrufen, Erstellen, Aktualisieren und Löschen von Kundenkonten sowie das Exportieren von Daten und das Zurücksetzen von Passwörtern. Zusätzlich können Informationen über bereits gelöschte Konten abgerufen werden. Für jede Operation gelten unterschiedliche Berechtigungen, die sicherstellen, dass nur autorisierte Benutzer auf die jeweiligen Funktionen zugreifen können. ### GET customerAccounts Mit dieser Methode wird eine paginierte Liste aller Kunden im Shop-System abgerufen. Neben grundlegenden Kundeninformationen wie ID, E-Mail-Adresse und Telefonnummer enthält jede Antwort auch zugehörige Adress- und Bankdaten. Über optionale Filter- und Sortierparameter lassen sich die Ergebnisse gezielt einschränken und sortieren. Die maximale Anzahl an Ergebnissen pro Anfrage beträgt 300. Für den Zugriff auf diese Schnittstelle sind Leseberechtigungen für Kundendaten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/customerAccounts ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "addresses": [ { "city": "asdf", "country": { "isoAlpha2": "DE", "isoAlpha3": "DEU", "isoNum": "276", "name": "Deutschland" }, "firstName": "asdf", "id": 108, "lastName": "asdf", "zip": "99999", ... } ], "allSubshopsAllowed": false, "allowedSubshopIds": [ "deutsch", "english" ], "bankData": [ { "accountNumber": "", "bankCode": "", "bankName": "foo", "bic": "", "iban": "", "id": 7, "owner": "bar", ... } ], "createdAt": "2024-09-03T10:09:34.000Z", "customerNumber": "", "deleted": false, "email": "root@root.root", "id": 1, "loginBlocked": false, "passwordResetRequired": false, "phone": "" }, ... ], "nextPageToken": "NDA", "totalCount": 41 } ``` #### Filterfelder `id`, `customerNumber`, `loginBlocked`, `deleted`, `createdAt`, `updatedAt` #### Sortierfelder `id`, `customerNumber`, `loginBlockedAt`, `deletedAt`, `createdAt`, `updatedAt` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Kundendaten. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET customerAccounts/\{accountId} Diese Methode lädt die vollständigen Daten eines Kundenkontos anhand seiner ID. Die Antwort enthält neben den Stammdaten wie E-Mail-Adresse, Telefonnummer und Kundennummer auch Zusatzinformationen wie erlaubte Subshops, Bankdaten, Adressen und Metadaten (z. B. letzter Login oder verwendete Zahlungsart). Zum Zugriff auf diese Methode sind Leseberechtigungen für Kundendaten erforderlich. Wird kein Konto mit der angegebenen ID gefunden, wird ein entsprechender Fehler zurückgegeben. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/customerAccounts/1 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "addresses": [ ... ], "allSubshopsAllowed": false, "allowedSubshopIds": [ "deutsch", "english" ], "bankData": [ ... ], "createdAt": "2024-09-03T10:09:34.000Z", "customerNumber": "", "deleted": false, "displayName": "", "email": "root@root.root", "id": 1, "loginBlocked": false, "mainSubshop": "", "meta": { "currentLogin": "2024.12.19-10:43:01.435", "dataSets": { "accountBasketId": "", "lastUsedBillAddressId": 108, "lastUsedDeliveryAddressId": 108, "lastUsedPaymentMethodId": "prepayment", "lastUsedPseudoCCId": "", "lastUsedShippingMethodId": "dhl", "mainAddressId": 108 }, "emailVerificationState": 0, "invitationLinkValidUntil": "", "invitationStatus": "notSent", "lastChangedAt": "2024-09-03T10:09:34.000Z", "lastChangedBy": "shop", "lastLogin": "2024.12.18-20:56:30.823", "passwordLinkValidUntil": "" }, "passwordResetRequired": false, "phone": "" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Kundendaten. | | 404 Not Found | | Das Konto mit `id`=`{accountId}` wurde nicht gefunden. | ### GET customerDataDeleted Diese Methode liefert eine Liste von Kundendatensätzen, die als gelöscht markiert wurden. Jeder Eintrag enthält die ID des Kontos, den Zeitpunkt der Löschung (`deletedAt`) sowie einen Typenwert, der die Art der gelöschten Daten beschreibt. Filter- und Sortierparameter stehen zur Verfügung, um die Ergebnismenge gezielt einzuschränken. Leseberechtigungen für Kundendaten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/customerDataDeleted ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "deletedAt": "2024-10-02T11:22:41.000Z", "id": 4, "type": 0 }, ... ], "nextPageToken": "NDA", "totalCount": 41 } ``` #### Filterfelder `id`, `type`, `deletedAt` #### Sortierfelder `id`, `type`, `deletedAt` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Kundendaten. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### POST customerAccounts Diese Methode erstellt ein neues Kundenkonto. Neben Basisdaten wie E-Mail-Adresse, Telefonnummer oder Passwort können auch Einstellungen zur Subshop-Zuweisung und bevorzugten Adressen übergeben werden. Der Request-Body muss mindestens eine gültige E-Mail-Adresse und ein Passwort enthalten. Weitere optionale Felder wie `mainAddress` oder `allowedSubshopIds` ermöglichen eine feinere Konfiguration des Kontos. Optional kann eine `accountId` (positive Ganzzahl) mitgegeben werden, um das Konto mit einer bestimmten ID anzulegen. Wird keine `accountId` angegeben, vergibt das System automatisch eine neue ID. Erstellrechte für Kundendaten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/customerAccounts ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "allSubshopsAllowed": false, "allowedSubshopIds": [ "deutsch" ], "createdAt": "2024-09-03T10:09:34.000Z", "customerNumber": "", "deleted": false, "displayName": "", "email": "root@root.root", "id": 1, "loginBlocked": false, "mainSubshop": "", "meta": { "currentLogin": "", "dataSets": { "accountBasketId": "", "lastUsedBillAddressId": 0, "lastUsedDeliveryAddressId": 0, "lastUsedPaymentMethodId": "", "lastUsedPseudoCCId": "", "lastUsedShippingMethodId": "", "mainAddressId": 0 }, "emailVerificationState": 0, "invitationLinkValidUntil": "", "invitationStatus": "notSent", "lastChangedAt": "2024-09-03T10:09:34.000Z", "lastChangedBy": "adminInterface", "lastLogin": "", "passwordLinkValidUntil": "" }, "passwordResetRequired": false, "phone": "" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Kundendaten. | | 400 Bad Request | | Request body konnte nicht geladen werden, oder das Erstellen ist fehlgeschlagen. | | 400 Bad Request | "unknownDataField" | Man versucht, etwas außer `accountId`, `customerNumber`, `email`, `phone`, `mainAddress`, `lastUsedBillAddressId`, `lastUsedDeliveryAddressId`, `password`, `passwordResetRequired`, `allSubshopsAllowed`, `allowedSubshopIds`, `displayName`, `mainSubshop`, `paymentLimit`, `paymentLimitPerOrder`, `enabledPaymentMethods` oder `blockedPaymentMethods` zu aktualisieren. | | 400 Bad Request | "invalidValue" | Eine Subshop-Id ist ungültig. | | 400 Bad Request | "invalidFormat" | `allowedSubshopIds`, `enabledPaymentMethods` oder `blockedPaymentMethods` sind kein Array von Strings.
    `allSubshopsAllowed` ist kein Boolean.
    `customerNumber`, `phone`, `email`, `password` sind keine Strings.
    `mainAddress`, `lastUsedDeliveryAddressId` oder `lastUsedBillAddressId` sind keine Zahlen.
    Die E-Mail-Adresse hat ein ungültiges Format. | | 400 Bad Request | "missing" | `email` oder `password` wurden nicht übergeben. | | 409 Conflict | | E-Mail oder Telefonnummer werden bei einem anderen Konto verwendet. | ### POST customerAccounts/\{accountId}/passwordReset Diese Methode versendet einen Link zum Zurücksetzen des Passworts an die im Kundenkonto hinterlegte E-Mail-Adresse. Das ist hilfreich, wenn ein Benutzer den Zugriff auf sein Konto verloren hat oder das Passwort zurücksetzen möchte. Schreibrechte für Kundendaten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/customerAccounts/1/passwordReset ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "passwordLinkValidUntil": "2025-09-12T12:51:59.000Z", "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Kundendaten. | | 400 Bad Request | "invalidValue" | `accountId` ist keine positive Ganzzahl.
    Die E-Mail-Adresse ist ungültig. | | 404 Not Found | | Das Konto mit `id`=`{accountId}` wurde nicht gefunden. | | 400 Bad Request | "missing" | Das Konto hat keine E-Mail-Adresse hinterlegt. | | 409 Conflict | | Ein Passwort-Reset-Link wurde innerhalb der letzten 24 Stunden bereits gesendet. | | 503 Service Unavailable | | Interner Fehler beim Versenden des Passwort-Reset-Links. | ### PUT customerAccounts/\{accountId} Mit dieser Methode wird ein bestehendes Kundenkonto anhand seiner ID aktualisiert. Es können unter anderem E-Mail-Adresse, Telefonnummer, Adressverweise und die Subshop-Zuordnung geändert werden. Schreibrechte für Kundendaten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/customerAccounts/1 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "m.mustermann@email.com", "passwordResetRequired": true, "allowedSubshopIds": [ "deutsch", "english" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "allSubshopsAllowed": false, "allowedSubshopIds": [ "deutsch" ], "createdAt": "2024-09-03T10:09:34.000Z", "customerNumber": "", "deleted": false, "displayName": "", "email": "root@root.root", "id": 1, "loginBlocked": false, "mainSubshop": "", "meta": { "currentLogin": "2024.12.19-10:43:01.435", "dataSets": { "accountBasketId": "", "lastUsedBillAddressId": 108, "lastUsedDeliveryAddressId": 108, "lastUsedPaymentMethodId": "prepayment", "lastUsedPseudoCCId": "", "lastUsedShippingMethodId": "dhl", "mainAddressId": 108 }, "emailVerificationState": 0, "invitationLinkValidUntil": "", "invitationStatus": "notSent", "lastChangedAt": "2024-09-03T11:00:00.000Z", "lastChangedBy": "adminInterface", "lastLogin": "2024.12.18-20:56:30.823", "passwordLinkValidUntil": "" }, "passwordResetRequired": false, "phone": "" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Kundendaten. | | 404 Not Found | | Das Konto mit `id`=`{accountId}` wurde nicht gefunden. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "unknownDataField" | Man versucht, etwas außer `customerNumber`, `email`, `phone`, `mainAddress`, `lastUsedBillAddressId`, `lastUsedDeliveryAddressId`, `passwordResetRequired`, `allSubshopsAllowed`, `allowedSubshopIds`, `displayName`, `mainSubshop`, `paymentLimit`, `paymentLimitPerOrder`, `enabledPaymentMethods` oder `blockedPaymentMethods` zu aktualisieren. | | 400 Bad Request | "invalidValue" | Eine Subshop-Id ist ungültig. | | 400 Bad Request | "invalidFormat" | `allowedSubshopIds`, `enabledPaymentMethods` oder `blockedPaymentMethods` sind kein Array von Strings.
    `allSubshopsAllowed` ist kein Boolean.
    `customerNumber`, `phone` oder `email` sind keine Strings.
    `mainAddress`, `lastUsedDeliveryAddressId` oder `lastUsedBillAddressId` sind keine Zahlen.
    Die E-Mail-Adresse hat ein ungültiges Format. | | 409 Conflict | | E-Mail oder Telefonnummer werden bei einem anderen Konto verwendet. Die Antwort enthält ein Feld `fieldName`, das angibt, welches Feld den Konflikt verursacht hat (z. B. `"email"` oder `"phone"`). | ### DELETE customerAccounts/\{accountId} Mit dieser Methode wird ein Kundenkonto anhand seiner ID gelöscht. Die Löschung ist dauerhaft und entfernt das Konto einschließlich aller zugehörigen Daten aus dem System. Löschrechte für Kundendaten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/customerAccounts/1 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Kundendaten. | | 404 Not Found | | Das Konto wurde nicht gefunden. | ### GET customerAccounts/deleted Gibt eine paginierte Liste gelöschter Kundenkonten zurück. Diese Methode ergänzt `GET customerDataDeleted` (Abschnitt 3.3), die gelöschte Adress- und Bankdaten liefert. Leserechte für Kundendaten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/customerAccounts/deleted ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "id": 42, "deletedAt": "2025-06-15T10:30:00.000Z" } ], "nextPageToken": "", "totalCount": 1 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Kundendaten. | | 400 Bad Request | "invalidParams" | Ungültige Such- oder Filterparameter. | ### POST customerAccounts/\{accountId}/activate Aktiviert ein Kundenkonto und versendet eine Einladungs-E-Mail an die hinterlegte E-Mail-Adresse. Das Konto muss eine verifizierte E-Mail-Adresse besitzen (bzw. die E-Mail-Verifizierung muss in der Konfiguration deaktiviert sein). Einladungslinks können maximal einmal pro 24 Stunden versendet werden. Schreibrechte für Kundendaten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/customerAccounts/1/activate ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "invitationLinkValidUntil": "2025-09-12T12:51:59.000Z", "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Kundendaten. | | 400 Bad Request | "invalidValue" | `accountId` ist keine gültige positive Ganzzahl.
    Die `stage` ist ungültig (nur "active" oder "work" erlaubt).
    Die E-Mail-Adresse ist ungültig. | | 400 Bad Request | "missing" | Das Konto hat keine E-Mail-Adresse hinterlegt (`email` fehlt). | | 400 Bad Request | | Die E-Mail-Adresse des Kontos ist nicht verifiziert und die E-Mail-Verifizierung ist in der Konfiguration aktiviert. | | 404 Not Found | | Das Konto wurde nicht gefunden. | | 409 Conflict | | Es wurde innerhalb der letzten 24 Stunden bereits eine Einladung versendet. | | 503 Service Unavailable | | Interner Fehler beim Versenden der Einladungs-E-Mail. | ### GET customerAccounts/\{accountId}/link Erzeugt einen temporären Login-Link, über den sich ein Kunde direkt im Shop einloggen kann. Der Link ist 30 Sekunden gültig. Schreib- und Löschrechte für Kundendaten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/customerAccounts/1/link ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "link": "https://www..de?sessionKey=abc123...", "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------- | ------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Schreib- und Löschrechte für Kundendaten. | | 404 Not Found | | Das Konto wurde nicht gefunden. | | 503 Service Unavailable | Internal error | Redis-Service ist nicht verfügbar.
    Das Senden der E-Mail ist fehlgeschlagen. | ## Methoden für Adressen und Bankdaten In diesem Abschnitt werden die Methoden zur Verwaltung von Adressen und Bankdaten innerhalb eines Kundenkontos beschrieben. Beide Datentypen werden strukturell gleich behandelt: Die Speicherung und das Laden erfolgen auf dieselbe Weise. Der Unterschied liegt ausschließlich im Endpunkt – statt `addresses` wird für Bankdaten `bankData` in der URL verwendet. ### GET customerAccounts/\{accountId}/addresses Mit dieser Methode können alle zur Verfügung stehenden Adressen eines bestimmten Kundenkontos abgerufen werden. Die Anfrage liefert eine Liste aller Adressdatensätze, die mit dem angegebenen Konto verknüpft sind. Der hier beschriebene Endpunkt gilt analog auch für Bankdaten – ersetzen Sie dafür im Pfad einfach `addresses` durch `bankData`. Für den Zugriff ist eine entsprechende Leseberechtigung erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/customerAccounts/1/addresses ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "additionalInfo": "", "addressType": "1", "businessFax": "", "businessPhone": "", "city": "asdf", "company": "WEBSALE AG", "country": { "isoAlpha2": "DE", "isoAlpha3": "DEU", "isoNum": "276", "name": "Deutschland" }, "custom": null, "dateOfBirth": "14.07.1967", "department": "", "externalId": "", "fax": "", "firstName": "asdff", "id": 5, "labels": [], "lastName": "asdf", "mobilePhone": "", "phone": "+49123456789", "salutationCode": "1", "state": "", "street": "asdf", "streetNumber": "9", "taxId": "", "titleCode": "2", "zip": "99999" }, { "additionalInfo": "", "addressType": "", "businessFax": "", "businessPhone": "", "city": "", "company": "", "country": "", "custom": null, "dateOfBirth": "", "department": "", "externalId": "", "fax": "", "firstName": "", "id": 141, "labels": [], "lastName": "", "mobilePhone": "", "phone": "", "salutationCode": "", "state": "", "street": "", "streetNumber": "", "taxId": "", "titleCode": "", "zip": "" } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Kundendaten. | | 404 Not Found | | Das Konto mit `id`=`{accountId}` wurde nicht gefunden. | ### GET customerAccounts/\{accountId}/addresses/\{id} Diese Methode liefert die Details einer einzelnen Adresse, die einem bestimmten Kundenkonto zugeordnet ist. Die Adresse wird anhand ihrer ID abgerufen. Der hier beschriebene Endpunkt gilt analog auch für Bankdaten – ersetzen Sie dafür im Pfad einfach `addresses` durch `bankData`. Der Zugriff erfordert eine gültige Leseberechtigung für Kundendaten. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/customerAccounts/1/addresses/5 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "additionalInfo": "", "addressType": "1", "businessFax": "", "businessPhone": "", "city": "asdf", "company": "WEBSALE AG", "country": { "isoAlpha2": "DE", "isoAlpha3": "DEU", "isoNum": "276", "name": "Deutschland" }, "custom": null, "dateOfBirth": "", "department": "", "externalId": "", "fax": "", "firstName": "asdff", "id": 5, "labels": [], "lastName": "asdf", "mobilePhone": "", "phone": "+49123456789", "salutationCode": "1", "state": "", "street": "asdf", "streetNumber": "9", "taxId": "", "titleCode": "2", "zip": "99999" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ----------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Kundendaten. | | 404 Not Found | | Das Konto mit `id`=`{accountId}` wurde nicht gefunden.
    Die Adresse wurde nicht gefunden. | ### POST customerAccounts/\{accountId}/addresses Mit dieser Methode wird eine neue Adresse für ein bestimmtes Kundenkonto angelegt. Die erforderlichen Felder für die Adresse werden im Request Body angegeben. Die Validierung erfolgt serverseitig, und fehlerhafte Felder werden in der Serverantwort konkret benannt. Der hier beschriebene Endpunkt gilt analog auch für Bankdaten – ersetzen Sie dafür im Pfad einfach `addresses` durch `bankData`. Für die Ausführung sind Schreib- und Erstellrechte für Kundendaten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/customerAccounts/1/addresses ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "custom": {}, "addressType": "1", "salutationCode": "1", "lastName": "Mustermann", "firstName": "Max", "street": "Musterstraße", "streetNumber": "54", "zip": "12345", "city": "Musterstadt", "country": "DE", "dateOfBirth": "14.07.1967", "phone": "+49123456789" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "additionalInfo": "", "addressType": "1", "businessFax": "", "businessPhone": "", "city": "Musterstadt", "company": "", "country": { "isoAlpha2": "DE", "isoAlpha3": "DEU", "isoNum": "276", "name": "Deutschland" }, "custom": null, "dateOfBirth": "14.07.1967", "department": "", "externalId": "", "fax": "", "firstName": "Max", "id": 158, "labels": [], "lastName": "Mustermann", "mobilePhone": "", "phone": "+49123456789", "salutationCode": "1", "state": "", "street": "Musterstrasse", "streetNumber": "54", "taxId": "", "titleCode": "", "zip": "12345" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Schreib- und Erstellrechte für Kundendaten. | | 400 Bad Request | | Request body konnte nicht geladen werden.
    Das Aktualisieren ist fehlgeschlagen. | | 400 Bad Request | "unknownDataField" | Es wird ein unbekanntes Feld aktualisiert. | | 400 Bad Request | "invalidFormat" | `custom` ist kein Objekt.
    `externalId` ist kein String.
    `labels` ist kein Array oder enthält Nicht-String-Werte. | | 404 Not found | | Die Adresse wurde nicht gefunden. | ### PUT customerAccounts/\{accountId}/addresses/\{id} Mit dieser Methode wird eine vorhandene Adresse eines Kundenkontos aktualisiert. Nur die übergebenen Felder werden geändert, eine vollständige Adressstruktur ist nicht erforderlich. Die Validierung erfolgt serverseitig – fehlerhafte Felder werden in der Antwort ausgewiesen. Der hier beschriebene Endpunkt gilt analog auch für Bankdaten – ersetzen Sie dafür im Pfad einfach `addresses` durch `bankData`. Für die Ausführung ist die Berechtigung zum Schreiben von Kundendaten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/customerAccounts/1/addresses/5 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "custom": {}, "zip": "99999", "firstName": "foo" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "additionalInfo": "", "addressType": "1", "businessFax": "", "businessPhone": "", "city": "Musterstadt", "company": "", "country": { "isoAlpha2": "DE", "isoAlpha3": "DEU", "isoNum": "276", "name": "Deutschland" }, "custom": null, "dateOfBirth": "14.07.1967", "department": "", "externalId": "", "fax": "", "firstName": "foo", "id": 5, "labels": [], "lastName": "Mustermann", "mobilePhone": "", "phone": "+49123456789", "salutationCode": "1", "state": "", "street": "Musterstrasse", "streetNumber": "54", "taxId": "", "titleCode": "2", "zip": "99999" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Kundendaten. | | 400 Bad Request | | Request body konnte nicht geladen werden.
    Das Aktualisieren ist fehlgeschlagen. | | 400 Bad Request | "unknownDataField" | Es wird ein unbekanntes Feld aktualisiert. | | 400 Bad Request | "invalidFormat" | `custom` ist kein Objekt.
    `externalId` ist kein String.
    `labels` ist kein Array oder enthält Nicht-String-Werte. | | 404 Not found | | Die Adresse wurde nicht gefunden. | ### DELETE customerAccounts/\{accountId}/addresses/\{id} Mit dieser Methode wird eine Adresse aus einem Kundenkonto gelöscht. Dabei wird überprüft, ob die Adresse tatsächlich zum angegebenen Konto gehört. Der hier beschriebene Endpunkt gilt analog auch für Bankdaten – ersetzen Sie dafür im Pfad einfach `addresses` durch `bankData`. Für die Ausführung sind Schreib- und Löschrechte für Kundendaten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/customerAccounts/1/addresses/5 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ----------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Schreib- und Löschrechte für Kundendaten. | | 404 Not Found | | Das Konto mit `id`=`{accountId}` wurde nicht gefunden.
    Die Adresse wurde nicht gefunden. | | 409 Conflict | | `{accountId}` und die Id des Kontos, zu dem die Adresse gehört, stimmen nicht überein. | ## Bulk-Methoden In diesem Abschnitt werden die Bulk-Endpunkte beschrieben, mit denen mehrere Datensätze in einem einzigen Request abgefragt oder verarbeitet werden können. ### GET bulk/lastOrderTimestamp Gibt den Zeitstempel der letzten Bestellung für mehrere Kundenkonten zurück. Ungültige Account-IDs und Konten ohne Bestellungen werden übersprungen. Leserechte für Kundendaten sind erforderlich. Der Pflichtparameter `accountId` (Integer) gibt die Kundenkonto-ID an und kann mehrfach angegeben werden, um mehrere Konten abzufragen. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/bulk/lastOrderTimestamp?accountId=1&accountId=2&accountId=3 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "accountId": 1, "lastOrderTimestamp": "2025-01-15T10:30:00Z" }, { "accountId": 3, "lastOrderTimestamp": "2025-03-20T14:22:00Z" } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Kundendaten. | ### POST bulk/customerAccounts Ermöglicht das massenhafte Erstellen und Aktualisieren von Kundenkonten in einem einzigen Request. Der Request-Body ist ein JSON-Array, in dem jedes Element eine Aktion (create oder update) beschreibt. Erstell- und Schreibrechte für Kundendaten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/bulk/customerAccounts ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "type": "create", "data": { "email": "neu@example.com", "firstName": "Max", "lastName": "Mustermann" } }, { "type": "update", "accountId": 42, "data": { "firstName": "Maria" } } ] ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [101, 42], "skippedLines": [ { "lineNumber": 3, "errorType": "invalidParameters", "fieldErrors": { "email": { "type": "missing" } } } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Erstell- und Schreibrechte für Kundendaten. | | 400 Bad Request | "invalidFormat" | Der Request-Body ist kein JSON-Array oder die maximale Anzahl an Einträgen wurde überschritten. | | skippedLines | "invalidParameters" | Pflichtfelder fehlen (z. B. `type`), Feldtyp stimmt nicht überein, ungültiger Wert für `type` (nicht `"create"` oder `"update"`), oder `accountId` fehlt bei `"update"`. | | skippedLines | "invalidFields" | Ungültige Felder beim Aktualisieren eines Kundenkontos. | | skippedLines | "conflict" | E-Mail-Adresse oder Kundennummer bereits vergeben. | | skippedLines | "notFound" | Kundenkonto mit der angegebenen `accountId` wurde nicht gefunden. | | skippedLines | "internalError" | Interner Fehler beim Erstellen des Kundenkontos. | ### POST bulk/customerAccounts/addresses Ermöglicht das massenhafte Erstellen und Aktualisieren von Kundenadressen in einem einzigen Request. Der Request-Body ist ein JSON-Array, in dem jedes Element eine Aktion (create oder update) für eine Adresse beschreibt. Erstell- und Schreibrechte für Kundendaten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/bulk/customerAccounts/addresses ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "type": "create", "accountId": 42, "data": { "firstName": "Max", "lastName": "Mustermann", "street": "Musterstraße 1", "zip": "12345", "city": "Musterstadt" } }, { "type": "update", "accountId": 42, "addressId": 7, "data": { "city": "Berlin" } } ] ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [15, 7], "skippedLines": [ { "lineNumber": 3, "errorType": "notFound", "fieldErrors": {} } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Erstell- und Schreibrechte für Kundendaten. | | 400 Bad Request | "invalidFormat" | Der Request-Body ist kein JSON-Array oder die maximale Anzahl an Einträgen wurde überschritten. | | skippedLines | "invalidParameters" | Pflichtfelder fehlen (z. B. `type`, `accountId`), Feldtyp stimmt nicht überein, ungültiger Wert für `type` (nicht `"create"` oder `"update"`), `addressId` fehlt bei `"update"`, oder ungültige Adressdaten. | | skippedLines | "notFound" | Kundenkonto mit der angegebenen `accountId` oder Adresse mit der angegebenen `addressId` wurde nicht gefunden. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Log Manager Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-log-manager Shop-Logs über die Admin Interface API abrufen, nach Schweregrad, Subshop oder Zeitstempel filtern und eigene Log-Gruppen verwalten. Die Schnittstelle unter dem Endpunkt `logmanager/` bietet Zugriff auf die im Shopsystem erfassten Logs. Sie ermöglicht das Abrufen einzelner Logs oder ganzer Log-Listen sowie die gezielte Analyse durch Filterung nach Parametern wie Schweregrad, Subshop oder Zeitstempel. Zusätzlich können Log-Gruppen erstellt und verwaltet werden, um spezifische Filterkriterien zu speichern und Benachrichtigungen bei neuen relevanten Einträgen zu erhalten. Die API unterstützt damit sowohl die manuelle Analyse als auch eine automatisierte Überwachung von Systemereignissen. Zur Nutzung der Schnittstellen sind entsprechende Zugriffsrechte erforderlich. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | ---------------------- | --------------------- | --------------------- | --------------------- | --------------------- | --------------------- | | **Logs** | logmanager/logs | | | | | | **Log-Gruppen** | logmanager/groups | | | | | | **Benachrichtigungen** | | | | | | ## Ressourcen: Felder in Logs ### Wichtige Datenfelder in Logs Logs im System basieren auf Daten aus *Elasticsearch* und unterliegen daher keiner starren Struktur. Dennoch gibt es zentrale Felder, die in nahezu allen Log-Einträgen vorkommen und für Filter, Sortierung oder Auswertung genutzt werden können. Die folgende Übersicht listet die wichtigsten dieser Felder: | **Name** | **Typ** | **Verwendung** | | ------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | **@timestamp** | String | Zeitpunkt der Erstellung | | **\_id** | String | Eindeutige ID des Logs | | **app** | String | Name des Programms, das das Log generiert hat (z.B. `reastapi`, `shop`, `statisticAggregator`) | | **logger** | String | Name des Loggers, der der Kategorisierung dient (z.B. `restapi.controllers.customers`) | | **msg** | String | Die Nachricht des Logs | | **sessionId (optional)** | String | Eindeutige ID der Sitzung, in der das Log generiert wurde | | **severity** | String | Schweregrad des Logs, der der Kategorisierung dient.
    Mögliche Werte:
    `debug`
    `info`
    `warning`
    `err`
    `crit` | | **shopId** | String | Der technische Name des Shops | | **stageId (optional)** | String | Stage, auf der das Log generierte wurde | | **subshopId (optional)** | String | Subshop, in dem das Log generiert wurde | **Hinweis:** Weitere Felder können abhängig vom Ursprung und Kontext des Logs vorhanden sein. Die tatsächliche Struktur einzelner Log-Einträge kann abweichen. #### Beispiel Der folgende Log-Eintrag stammt aus dem System und zeigt typische Felder, wie sie von Elasticsearch geliefert werden. Optional enthaltene Felder wie `agent`, `host` oder `tags` können je nach Ursprung des Logs variieren. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "@timestamp": "2025-05-07T06:51:15.148Z", "@version": "1", "_id": "KJGDqZYBCZfVknTATek6", "agent": { "ephemeral_id": "166b1b26-3479-44a0-abd5-01eb97dfde6a", "hostname": "849eec2f201d", "id": "1bac5950-93cd-45c0-83ef-96f0f835523b", "name": "849eec2f201d", "type": "filebeat", "version": "7.17.3" }, "app": "restapi", "ecs": { "version": "1.12.0" }, "host": { "name": "849eec2f201d" }, "hostname": "db762f83481f", "input": { "type": "log" }, "log": { "file": { "path": "/opt/ws/v9-logs/restapi/2025_05_07.log" }, "offset": 4746 }, "logger": "restapi.controller.statistics", "msg": "Failed to get yesterday's active visitors: {\"error\":{\"root_cause\":[{\"type\":\"index_not_found_exception\",\"reason\":\"no such index [visitors]\",\"resource.type\":\"index_or_alias\",\"resource.id\":\"visitors\",\"index_uuid\":\"_na_\",\"index\":\"visitors\"}],\"type\":\"index_not_found_exception\",\"reason\":\"no such index [visitors]\",\"resource.type\":\"index_or_alias\",\"resource.id\":\"visitors\",\"index_uuid\":\"_na_\",\"index\":\"visitors\"},\"status\":404}", "severity": "err", "shopId": "myshop", "tags": [ "v9", "beats_input_raw_event" ] } ``` ### Programme, die Logs erzeugen Das Feld `app` in einem Logeintrag gibt an, welches Programm oder welcher Dienst das Log erzeugt hat. Die folgende Übersicht listet die möglichen Programme auf, die in der Praxis als `app`-Wert erscheinen können – inklusive einer kurzen Beschreibung ihrer Aufgabe innerhalb des Shop-Systems. | **Werte A - Z (app)** | **Beschreibung** | | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `admin` | Backend-Interface für die Shop-Verwaltung | | `appAutomation` | Automatisierungsprozesse im Shop-System | | `asse` | Automatischer Dienst zur Ausführung und Zustellung serverseitiger HTTP-Benachrichtigungen (Asynchronous Server Side Events) | | `backInStock` | Verwaltung von Benachrichtigungen bei wieder verfügbaren Artikeln | | `cache` | Aktualisieren vom Cache | | `captureExecutor` | Verarbeitet automatisch Zahlungs-Capture-Dateien für Bestellungen, führt bei Bedarf Zahlungsaufforderungen an den Zahlungsanbieter durch und verwaltet Wiederholungsversuche sowie Fehlerbehandlung. | | `categoryProductsRebuilder` | Prozess, der Produkte Kategorien mit regelbasierter Produktzuweisung automatisch zuordnet. | | `configUpdater` | Interner Dienst, der auf die Aktualisierung von Konfigurationsdaten reagiert | | `feedBuilder` | Erstellung von Datenfeeds für Exporte und von Sitemaps | | `garbageCollector` | Automatische Bereinigung nicht mehr benötigter Daten | | `heartbeatChecker` | Überwachung von Hintergrundprogrammen | | `html2mime` | Umwandlung von HTML in E-Mails | | `imageChecker` | Prüft, ob es ungenutzte Produktbilder gibt und ob referenzierte Bilder existieren. | | `imageconverter` | Konvertiert Bilder in andere Formate | | `importer` | Import von Daten wie Produkten, Kundendaten etc. | | `mailbackup` | Sicherung versendeter E-Mails | | `mailer` | Versand von E-Mails aus dem System heraus | | `newsletterSubscribeHelper` | Prozess, der Double-Opt-In-E-Mails mit einer Einladung zur Newsletter-Anmeldung versendet. | | `notificator` | Benachrichtigungsdienst für die App | | `productRatingBackend` | Versand von Bewertungsanfragen | | `restapi` | Logs aus der REST-API | | `searchindexer` | Indizierung von Produkten für die Shopsuche | | `shop` | Allgemeiner Shop-Prozess (z. B. Warenkorb, Checkout, Navigation) | | `spChecker` | Mo­ni­to­ring der System-Points-Nutzung | | `statisticAggregator` | Aggregation und Aufbereitung statistischer Daten | | `templateCompiler` | Kompiliert Templates, kann über die REST API gestartet werden | ## Methoden für Logs Über die nachfolgenden Endpunkte lassen sich Log-Einträge aus dem System abrufen. Die Logs enthalten detaillierte Informationen zu Ereignissen im Shop, wie z. B. Fehlermeldungen, Debug-Ausgaben oder sicherheitsrelevante Hinweise. Einträge können gefiltert und sortiert sowie einzeln nach ihrer ID geladen werden. Für den Zugriff auf diese Daten sind entsprechende Leseberechtigungen erforderlich. ### GET logmanager/logs Über diesen Endpunkt kann eine Liste mit Logeinträgen abgefragt werden. Die Ergebnisse lassen sich nach Zeitstempel, Schweregrad (`severity`), Shop, Subshop, Logger, Session-ID oder weiteren Feldern filtern und sortieren. Standardmäßig wird nach dem Feld `@timestamp` sortiert. Für die Abfrage kann ein Zeitraum mit `filter_gte[createdAt]` und `filter_lte[createdAt]` angegeben werden. Der Zugriff ist auf maximal 300 Einträge pro Anfrage begrenzt, eine Paginierung erfolgt über `nextPageToken`. Die maximale Anzahl an Ergebnissen beträgt 10.000 - auch bei Paginierung. Darüber hinausgehende Daten können nicht abgerufen werden. Zur Verfügung stehen Logs verschiedener Anwendungen (z. B. `shop`, `restapi`) und Quellen (z. B. `filebeat`). Sie enthalten strukturierte Metadaten und Fehlermeldungen, die zur Analyse von Prozessen oder Fehlern im Shop dienen. Um die tatsächlichen Logdateien oder Pfade zu ermitteln, kann das Feld `log.file.path` genutzt werden. #### Beispiel Zugriff auf bis zu 100 Logs aller Art im Zeitraum 2025.03.24–2025.04.24 ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/logmanager/logs?size=100&sort=@timestamp:asc&filter_eq[severity]=debug&filter_eq[severity]=info&filter_eq[severity]=warning&filter_eq[severity]=err&filter_eq[severity]=crit&filter_gte[createdAt]=2025-03-24T00:00:00.371Z&filter_lte[createdAt]=2025-04-23T23:59:59.371Z&filter_eq[subshopId]=deutsch ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": false, "items": [ { "@timestamp": "2025-04-04T13:41:51.097Z", "@version": "1", "_id": "9e2uHpYBZKNjyb2oXatY", "agent": { "ephemeral_id": "70e334c2-f5ac-4599-aa32-dd5dc7d7551d", "hostname": "9f46d9c66ba8", "id": "1bac5950-93cd-45c0-83ef-96f0f835523b", "name": "9f46d9c66ba8", "type": "filebeat", "version": "7.17.3" }, "app": "shop", "ecs": { "version": "1.12.0" }, "host": { "name": "9f46d9c66ba8" }, "hostname": "f87daf6dd2fe", "input": { "type": "log" }, "log": { "file": { "path": "/opt/ws/v9-logs/shop/2025_04_04.log" }, "offset": 5825 }, "logger": "form", "msg": "Missing recaptcha parameters:\nverifyUrl='https://www.google.com/re...", "sessionId": "973dda5db818b2a57942baed66f27f0939f78ee162b6bb65490e8fea3772791e", "severity": "crit", "shopId": "myshop", "stageId": "3", "subshopId": "deutsch", "tags": [ "v9", "beats_input_raw_event" ] }, { "@timestamp": "2025-04-09T13:17:57.461Z", "@version": "1", "_id": "iu7LHpYBZKNjyb2o-KEm", "agent": { "ephemeral_id": "70e334c2-f5ac-4599-aa32-dd5dc7d7551d", "hostname": "9f46d9c66ba8", "id": "1bac5950-93cd-45c0-83ef-96f0f835523b", "name": "9f46d9c66ba8", "type": "filebeat", "version": "7.17.3" }, "app": "shop", "ecs": { "version": "1.12.0" }, "host": { "name": "9f46d9c66ba8" }, "hostname": "f87daf6dd2fe", "input": { "type": "log" }, "log": { "file": { "path": "/opt/ws/v9-logs/shop/2025_04_09.log" }, "offset": 85186 }, "logger": "product", "msg": "Meta title field of the product is not a string", "sessionId": "269300aab23352c10324f82817bcb12aaf433e325425753b3c89018cee7fc0fd", "severity": "err", "shopId": "myshop", "stageId": "3", "subshopId": "deutsch", "tags": [ "v9", "beats_input_raw_event" ] }, { "@timestamp": "2025-04-03T07:41:46.882Z", "@version": "1", "_id": "Hd7LYZYBUuEsdVP_P_eb", "agent": { "ephemeral_id": "71484722-483c-4c99-9436-b470708d50c7", "hostname": "0d81d1bd24c9", "id": "1bac5950-93cd-45c0-83ef-96f0f835523b", "name": "0d81d1bd24c9", "type": "filebeat", "version": "7.17.3" }, "app": "restapi", "ecs": { "version": "1.12.0" }, "host": { "name": "0d81d1bd24c9" }, "hostname": "2d3c543a9bfd", "input": { "type": "log" }, "log": { "file": { "path": "/opt/ws/v9-logs/restapi/2025_04_03.log" }, "offset": 93145 }, "logger": "data.products.repository", "msg": "Generating XML for combination", "severity": "info", "shopId": "myshop", "stageId": "3", "subshopId": "deutsch", "tags": [ "v9", "beats_input_raw_event" ] } ], "nextPageToken": "MTAw", "totalCount": 10000 } ``` #### Filterfelder `logger` (wenn nicht spezifiziert - alle), `createdAt` (statt `@timestamp`), weitere Felder eines Logs wie `subshopId`, `severity`, `app` #### Sortierfelder Es ist möglich, Logs nach unterschiedlichen Feldern zu sortieren (z.B. nach `sessionId.keyword`), aber standardmäßig wird nur die Sortierung nach `@timestamp` genutzt. #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------- | ---------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Logs . | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | | 503 Service Unavailable | "internalError" | Logs konnten nicht geladen werden. | ### GET logmanager/logs/\{id} Diese Methode lädt ein einzelnes Log-Ereignis anhand seiner ID. Es werden alle zugehörigen Felder wie Zeitstempel, Quelle, Schweregrad, Nachricht und Kontextinformationen zurückgegeben. Für die Nutzung dieser Methode müssen entsprechende Leserechte für Logs vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/logmanager/logs/4-yUHpYBZKNjyb2okM3P ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "@timestamp": "2025-04-01T15:38:07.934Z", "@version": "1", "agent": { "ephemeral_id": "70e334c2-f5ac-4599-aa32-dd5dc7d7551d", "hostname": "9f46d9c66ba8", "id": "1bac5950-93cd-45c0-83ef-96f0f835523b", "name": "9f46d9c66ba8", "type": "filebeat", "version": "7.17.3" }, "app": "shop", "ecs": { "version": "1.12.0" }, "host": { "name": "9f46d9c66ba8" }, "hostname": "f87daf6dd2fe", "input": { "type": "log" }, "log": { "file": { "path": "/opt/ws/v9-logs/shop/2025_04_01.log" }, "offset": 0 }, "logger": "router", "msg": "Path '/favicon.ico' not known", "sessionId": "8fd2e99fb7fe7da9c35f0685b8381f0ab6ac05ff159a0767e2f3b2e899d7aadf", "severity": "info", "shopId": "myshop", "stageId": "3", "subshopId": "deutsch", "tags": [ "v9", "beats_input_raw_event" ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | --------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Logs. | | 404 Not Found | | Das Log wurde nicht gefunden. | | 503 Service Unavailable | "internalError" | Das Log konnte nicht geladen werden. | ## Methoden für Log-Gruppen Über die folgenden Endpunkte lassen sich Log-Gruppen im Shop-System erstellen, abrufen, aktualisieren und löschen. Log-Gruppen definieren, welche Arten von Logs beobachtet werden sollen – z. B. nach Schweregrad, Subshop oder Quelle – und bilden damit die Grundlage für gezielte Auswertungen und Benachrichtigungen. Zusätzlich können Benachrichtigungseinstellungen einer Gruppe konfiguriert werden, um über neue Log-Einträge regelmäßig informiert zu werden. Zur Nutzung der Schnittstellen sind entsprechende Rechte zum Verwalten von Logs erforderlich. ### GET logmanager/groups Mit diesem Endpunkt lassen sich Log-Gruppen abfragen. Eine Log-Gruppe bündelt bestimmte Log-Einträge anhand eines konfigurierbaren Filters, z. B. nach Schweregrad oder Zeitraum. Die Ergebnisliste kann über Filter- und Sortierparameter gezielt eingeschränkt werden. Für den Zugriff auf diese Daten sind entsprechende Leseberechtigungen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/logmanager/groups?size=100 &filter_gte[createdAt]=2025-03-25T00:00:00.913Z &filter_lte[createdAt]=2025-04-25T23:59:59.913Z ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "createdAt": "2025-04-23T16:03:37.000Z", "description": "myDescription", "filter": { "or": [] }, "id": 4, "name": "myGroup", "notificationEnabled": false, "notificationId": 3 } ], "nextPageToken": "MA", "totalCount": 1 } ``` #### Filterfelder `id`, `name`, `description`, `notificationId`, `filter`, `createdAt` #### Sortierfelder `id`, `name`, `description`, `createdAt` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | --------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Logs. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET logmanager/groups/\{id} Mit diesem Endpunkt kann eine einzelne Log-Gruppe anhand ihrer ID abgerufen werden. Die Log-Gruppe enthält Metadaten wie Name, Beschreibung, Erstellungszeitpunkt, Filter und einen optionalen Verweis auf eine Benachrichtigungskonfiguration. Für den Zugriff sind entsprechende Leseberechtigungen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/logmanager/groups/4 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-04-23T16:03:37.000Z", "description": "myDescription", "filter": { "or": [] }, "id": 4, "name": "myGroup", "notificationId": 3 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | --------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Logs. | | 400 Bad Request | "invalidValue" | `id` fehlt oder ist ungültig. | | 404 Not Found | | Die Log-Gruppe wurde nicht gefunden. | ### GET logmanager/groups/\{id}/logs Mit diesem Endpunkt kann eine Liste von Logs abgerufen werden, die zu einer bestimmten Log-Gruppe gehören. Die ID der Log-Gruppe muss in der URL übergeben werden. Die Abfrage unterstützt Filterung, Sortierung sowie die Paginierung über die Parameter `size`, `sort` und `pageToken`. Für den Zugriff müssen entsprechende Leseberechtigungen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/logmanager/groups/3/logs?size=100 &filter_gte[createdAt]=2025-03-24T00:00:00.186Z &filter_lte[createdAt]=2025-04-25T23:59:59.186Z ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": false, "items": [ { "@timestamp": "2025-04-11T09:35:24.646Z", "@version": "1", "_id": "6ckRXZYBlnEc1Y7xhdd4", "agent": { "ephemeral_id": "823e4491-dab9-468c-98d4-d5303323ee16", "hostname": "0d81d1bd24c9", "id": "1bac5950-93cd-45c0-83ef-96f0f835523b", "name": "0d81d1bd24c9", "type": "filebeat", "version": "7.17.3" }, "app": "shop", "ecs": { "version": "1.12.0" }, "host": { "name": "0d81d1bd24c9" }, "hostname": "391a58954768", "input": { "type": "log" }, "log": { "file": { "path": "/opt/ws/v9-logs/shop/2025_04_11.log" }, "offset": 94691 }, "logger": "shop.parseView", "msg": "RenderView Time 72703 us", "sessionId": "b831971cb73728321b979bdd49906512fdc48efd4be5022011abecd4bec9da89", "severity": "debug", "shopId": "myshop", "tags": [ "v9", "beats_input_raw_event" ] }, ... ], "nextPageToken": "MTAw", "totalCount": 10000 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------- | --------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Logs. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | | 404 Not Found | | Die Log-Gruppe wurde nicht gefunden. | | 503 Service Unavailable | "internalError" | Logs konnten nicht geladen werden. | ### GET logmanager/groups/\{id}/notifications Mit diesem Endpunkt können die Benachrichtigungseinstellungen einer bestimmten Log-Gruppe abgerufen werden. Dazu gehören u. a. die Empfänger, der Benachrichtigungszeitraum und der Zeitpunkt des letzten Versands. Die ID der Log-Gruppe muss in der URL übergeben werden. Für den Zugriff sind entsprechende Leseberechtigungen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/logmanager/groups/3/notifications ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-04-23T15:08:56.000Z", "creator": 1, "enabled": true, "filter": { "or": [] }, "id": 2, "lastSentTimestamp": "2025-04-23T15:08:17.000Z", "logGroupId": 3, "notificationPeriod": 1440, "recipients": { "accounts": [ { "enabled": true, "id": 1 } ], "emails": [] }, "startDate": "2025-04-23T15:08:17.000Z", "subject": "asdf" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | --------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Logs. | | 400 Bad Request | "invalidValue" | `id` fehlt oder ist ungültig. | | 404 Not Found | | Die Log-Gruppe wurde nicht gefunden. | ### POST logmanager/groups Mit diesem Endpunkt kann eine neue Log-Gruppe erstellt werden. Pflichtfelder sind `name` und `filter`; das Feld `description` ist optional. Der Filter legt fest, welche Logs der Gruppe zugeordnet werden sollen. Die Filter bestehen aus geschachtelten logischen Bedingungen (z. B. `or`, `and`, `eq`). Für die Nutzung des Endpunkts müssen die erforderlichen Rechte zum Erstellen von Log-Gruppen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/logmanager/groups ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "asdf", "description": "fdsa", "filter": { "or": [ { "and": [ { "or": [ { "eq": { "app": "restapi.cgi" } } ] }, { "or": [ { "eq": { "logger": "restapi.controllers.products" } } ] }, { "or": [ { "eq": { "severity": "error" } }, { "eq": { "severity": "crit" } } ] }, { "or": [ { "eq": { "subshopId": "deutsch" } }, { "eq": { "subshopId": "english" } } ] } ] } ] } } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-04-23T16:03:37.000Z", "description": "fdsa", "filter": { "or": [ { "and": [ { "or": [ { "eq": { "app": "restapi.cgi" } } ] }, { "or": [ { "eq": { "logger": "restapi.controllers.products" } } ] }, { "or": [ { "eq": { "severity": "error" } }, { "eq": { "severity": "crit" } } ] }, { "or": [ { "eq": { "subshopId": "deutsch" } }, { "eq": { "subshopId": "english" } } ] } ] } ] }, "id": 1, "name": "asdf", "notificationId": 0 } ``` **Hinweis:** Eine neu erstellte Log-Gruppe hat stets `notificationId: 0`, da noch keine Benachrichtigungskonfiguration zugewiesen wurde. Diese kann anschließend über `PUT logmanager/groups/{id}/notifications` eingerichtet werden. #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | ------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Logs. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body übergeben. | | 400 Bad Request | "invalidFormat" | `name` oder `description` ist kein String.
    `filter` ist kein Objekt. | | 400 Bad Request | "invalidValue" | `name` ist ein leerer String. | | 400 Bad Request | "missing" | `name` oder `filter` wurden nicht übergeben. | | 503 Service Unavailable | "internalError" | Die neu erstellte Log-Gruppe konnte nicht geladen werden. | ### PUT logmanager/groups/\{id} Mit diesem Endpunkt kann eine bestehende Log-Gruppe anhand ihrer ID aktualisiert werden. Änderungen können z. B. den Namen, die Beschreibung oder das Filterobjekt der Gruppe betreffen. Wird ein Filter übergeben, muss dieser ein baumartiges Objekt sein. Für die Nutzung des Endpunkts müssen die erforderlichen Rechte zum Bearbeiten von Log-Gruppen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/logmanager/groups/4 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "myGroup", "description": "newDescription", "filter": { "or": [] } } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-04-23T16:03:37.000Z", "description": "newDescription", "filter": { "or": [] }, "id": 4, "name": "myGroup", "notificationId": 3 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Logs. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body übergeben. | | 400 Bad Request | "invalidValue" | `id` fehlt oder ist ungültig. | | 400 Bad Request | "invalidFormat" | `name` oder `description` ist kein String.
    `filter` ist kein Objekt. | | 404 Not Found | | Die Log-Gruppe wurde nicht gefunden. | ### PUT logmanager/groups/\{id}/notifications Mit diesem Endpunkt können die Benachrichtigungseinstellungen einer bestehenden Log-Gruppe anhand ihrer ID geändert werden. Dabei lassen sich z. B. Empfänger, Startzeitpunkt, Benachrichtigungsintervall sowie Betreff definieren oder anpassen. Zur Nutzung sind die entsprechenden Schreibrechte für Log-Gruppen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/logmanager/groups/3/notifications ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "enabled": true, "subject": "asdf", "recipients": { "accounts": [ { "id": 1, "enabled": true } ] }, "startDate": "2025-04-23T15:08:17.550Z", "notificationPeriod": 1440 } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-04-23T15:08:56.000Z", "creator": 1, "enabled": true, "filter": { "or": [] }, "id": 2, "lastSentTimestamp": "2025-04-23T15:08:17.000Z", "logGroupId": 3, "notificationPeriod": 1440, "recipients": { "accounts": [ { "enabled": true, "id": 1 } ], "emails": [] }, "startDate": "2025-04-23T15:08:17.000Z", "subject": "asdf" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Logs. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body übergeben. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "invalidFormat" | `enabled` ist kein Boolean.
    `subject` ist kein String.
    `recipients` ist kein Objekt.
    `notificationPeriod` ist keine positive Zahl.
    `startDate` ist kein String.
    `customSendTime` ist kein Boolean.
    `sendDate` ist kein String.
    `sendTime` ist kein String. | | 400 Bad Request | "missing" | `sendDate` oder `sendTime` wurden nicht übergeben, obwohl `customSendTime` auf `true` gesetzt ist. | | 404 Not Found | | Die Log-Gruppe wurde nicht gefunden. | ### PUT logmanager/groups/\{id}/notifications/enabled Mit diesem Endpunkt können die Benachrichtigungen einer bestehenden Log-Gruppe anhand ihrer ID de-/aktiviert werden. Existieren für die Log-Gruppe noch keine Benachrichtungseinstellungen, werden bei Aktivierung Default-Einstellungen erzeugt. Zur Nutzung sind die entsprechenden Schreibrechte für Log-Gruppen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/logmanager/groups/3/notifications/enabled ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "enabled": true } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Logs. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | Ungültiger Route Parameter `id` oder ungültiges `enabled` Feld in Request Body | | 404 Not Found | | Die Log-Gruppe wurde nicht gefunden. | ### DELETE logmanager/groups/\{id} Mit diesem Endpunkt kann eine bestehende Log-Gruppe anhand ihrer ID gelöscht werden. Damit werden auch die zugehörigen Benachrichtigungseinstellungen entfernt. Zur Ausführung sind entsprechende Löschrechte für Logs erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/logmanager/groups/2 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ----------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Logs. | | 400 Bad Request | "invalidValue" | `id` fehlt oder ist ungültig. | | 404 Not Found | | Die Log-Gruppe wurde nicht gefunden. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Meta-Daten Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-meta-daten SEO-Meta-Titel und Beschreibungen für Seiten, Kategorien und Produkte über die Admin Interface API pflegen oder auf Standardwerte zurücksetzen. Mit dem Endpunkt `seo/texts/` steht Ihnen eine Schnittstelle zur Verfügung, mit der Sie SEO-Meta-Daten für verschiedene Bereiche des Shops (z. B. Seiten, Kategorien, Produkte) verwalten können. Die API ermöglicht es, Meta-Titel und Meta-Beschreibungen manuell zu pflegen oder sie bei Bedarf auf die automatisch generierten Standardwerte zurückzusetzen. Meta-Daten werden dabei entweder direkt gesetzt oder auf Basis hinterlegter Schemata erzeugt. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | ------------------------------------------ | ----------------- | --------------------- | --------------------- | --------------------- | --------------------- | | **Meta-Daten der Shop-Seiten** | seo/texts/ | | | | | | **Zurücksetzen auf Standardeinstellungen** | seo/texts/…/reset | | | | | | **Aktualisierung aller SEO-Texte** | seo/texts/update | | | | | ## Datenfelder (Meta-Data Resource) Meta-Daten von Kategorie- und Produkt-Seiten werden in benutzerdefinierten Feldern `metaTitle` und `metaDescription` gespeichert. Um damit zu arbeiten, werden Endpunkte [**categories/**](/schnittstellen/admin-interface-api/api-referenz-kategorien) und [**products/**](/schnittstellen/admin-interface-api/api-referenz-produkte) verwendet. Meta-Daten der Start-Seite befinden sich in subshop-spezifischen Konfigurationen und können über API nicht abgefragt werden. Für Meta-Daten der sonstigen Shop-Seiten gibt es eine Tabelle in der Datenbank. ### Datenfelder | **Name** | **Typ** | **Bedeutung** | | ------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------- | | **id** | Integer | Eindeutige ID des Datensatzes | | **resourceId** | String | Eindeutiger Name der Seite einschließlich Pfad. | | **metaTitle** | String | Enthält den Meta-Titel der Seite. | | **metaTitleSetManually** | Boolean | Gibt an, ob der Meta-Titel manuell gesetzt ist und sich nach dem Aktualisieren vom Schema nicht ändern soll. | | **metaDescription** | String | Enthält die Meta-Beschreibung der Seite. | | **metaDescriptionSetManually** | Boolean | Gibt an, ob die Meta-Beschreibung manuell gesetzt ist und sich nach dem Aktualisieren vom Schema nicht ändern soll. | | **createdAt** | String | Zeitpunkt, zu dem die Meta-Daten erstellt wurden (ISO 8601-Format, UTC). | | **updatedAt** | String | Zeitpunkt der letzten Aktualisierung der Meta-Daten (ISO 8601-Format, UTC). | ### Beispiel von einem Datensatz ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-01-22 19:49:29", "id": 7, "metaDescription": "some text", "metaDescriptionSetManually": true, "metaTitle": "some generated text", "metaTitleSetManually": false, "resourceId": "newPage2", "updatedAt": "2025-01-22 19:49:34" } ``` ## Methoden für Meta-Daten von Shop-Seiten (Views) In diesem Abschnitt finden Sie alle Endpunkte zur Verwaltung von Meta-Daten für Shop-Seiten, die intern als *Views* bezeichnet werden. Sie können Meta-Daten wie Titel und Beschreibung aktualisieren oder zurücksetzen, Daten der vorhandenen Seiten abrufen, neue Seiten registrieren sowie einzelne Einträge löschen. Die Views werden über ihre `resourceId` eindeutig identifiziert. Rechte für SEO-Daten sind erforderlich. ### GET seo/texts/views Diese Methode liefert eine paginierte Liste von Meta-Daten (z. B. Titel und Beschreibung) aller im Shop vorhandenen Seitenressourcen, die für SEO-Zwecke gepflegt werden können. Mithilfe der Filter- und Sortierparameter lassen sich gezielt nur bestimmte Einträge laden – etwa nur Seiten mit manuell gesetzten Meta-Titeln oder -Beschreibungen. Die Anzahl der Einträge pro Seite kann mit dem Parameter `size` im Bereich von 1 bis 300 festgelegt werden. Zur Nutzung sind Leserechte für SEO-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/texts/views ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "createdAt": "2025-01-09 11:07:55", "id": 5, "metaDescription": "", "metaDescriptionSetManually": true, "metaTitle": "My page", "metaTitleSetManually": true, "resourceId": "newPage", "updatedAt": "2025-03-06 16:10:42" }, ... ], "nextPageToken": "NA", "totalCount": 5 } ``` #### Filterfelder `createdAt`, `updatedAt`, `metaTitleSetManually`, `metaDescriptionSetManually` #### Sortierfelder `createdAt`, `updatedAt`, `resourceId`, `metaTitle`, `metaDescription` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von SEO-Daten. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig.
    `size` ∉ \[1;300]
    `pageToken` ist keine Zahl oder kleiner als 0.
    `sort`-Richtung ist weder "asc" noch "desc". | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | | 503 Service Unavailable | "internalError" | Das Lesen von Daten ist fehlgeschlagen. | ### POST seo/texts/views Mit dieser Methode kann eine neue Shop-Seite zur SEO-Verwaltung registriert werden. Beim Anlegen werden `metaTitle` und `metaDescription` zunächst leer gespeichert. Es muss ein eindeutiger Seitenname (`viewName`) übergeben werden, der als `resourceId` dienen wird. Der Name darf noch nicht existieren. Für diese Aktion sind Erstellrechte für SEO-Daten erforderlich. **Hinweis**: Wenn eine neue Shop-Seite nicht manuell registriert wird, werden für sie Meta-Daten automatisch nach dem Schema aus der Konfiguration generiert, wenn auf sie zum ersten Mal zugegriffen wird. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/texts/views ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "viewName": "Über uns" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-01-22 19:49:29", "id": 7, "metaDescription": "", "metaDescriptionSetManually": false, "metaTitle": "", "metaTitleSetManually": false, "resourceId": "Über uns", "updatedAt": "2025-01-22 19:49:29" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von SEO-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig. | | 409 Conflict | "existsAlready" | Der Name steht schon in der Tabelle. | | 503 Service Unavailable | "internalError" | Die Seite konnte nicht registriert werden. | ### PUT seo/texts/views/\{viewId} Mit dieser Methode können die SEO-Meta-Daten (Titel und Beschreibung) einer bestimmten Shop-Seite gezielt aktualisiert werden. Es dürfen ausschließlich `metaTitle` und/oder `metaDescription` verändert werden – begleitende technische Felder wie `metaTitleSetManually`, `metaDescriptionSetManually` und `updatedAt` werden automatisch gesetzt. Die Angabe der `viewId` in der URL ist erforderlich. Es handelt sich dabei um die numerische `id` des Datensatzes (nicht die `resourceId`). Zum Aktualisieren müssen entsprechende Schreibrechte für SEO-Daten vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/texts/views/5 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "metaDescription": "Informieren Sie sich hier über die Allgemeinen Geschäftsbedingungen (AGB)" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-01-09 11:07:55", "id": 5, "metaDescription": "Informieren Sie sich hier über die Allgemeinen Geschäftsbedingungen (AGB)", "metaDescriptionSetManually": true, "metaTitle": "My page", "metaTitleSetManually": true, "resourceId": "agb", "updatedAt": "2025-03-06 16:10:42" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von SEO-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig.
    `viewId` ist keine gültige Zahl. | | 400 Bad Request | "missing" | `viewId` fehlt. | | 404 Not Found | | Es gibt keine Seite mit der angegebenen `id`. | | 503 Service Unavailable | "internalError" | Die Datenaktualisierung ist fehlgeschlagen. | ### PUT seo/texts/views/reset Dieser Endpunkt setzt die manuell gesetzten Meta-Daten ausgewählter Seiten zurück und ersetzt sie durch automatisch generierte Werte gemäß dem festgelegten Schema. Die Felder `metaTitleSetManually` und `metaDescriptionSetManually` werden dabei auf `false` gesetzt. Schreibrechte für SEO-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/texts/views/reset ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ "newPage", "newPage2" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von SEO-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig. | ### DELETE seo/texts/views/\{viewId} Mit diesem Endpunkt lassen sich die Meta-Daten (Titel und Beschreibung) einer registrierten Seite gezielt löschen. Die Seite wird anhand ihrer numerischen `id` identifiziert. Für die Ausführung sind Löschrechte für SEO-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/texts/views/5 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von SEO-Daten. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig.
    `viewId` ist keine gültige Zahl. | | 400 Bad Request | "missing" | `viewId` fehlt. | | 404 Not Found | | Die Seite wurde nicht gefunden. | ## Methoden für Meta-Daten von Kategorien Dieser Abschnitt behandelt die Verarbeitung von SEO-Meta-Daten für Kategorien. Die API erlaubt ausschließlich das Zurücksetzen manuell gepflegter Meta-Titeln und Meta-Beschreibungen. Dabei werden bestehende Inhalte entfernt und durch Werte ersetzt, die anhand eines Schemas generiert werden. ### PUT seo/texts/categories/reset Setzt die Meta-Daten der übergebenen Kategorien zurück. Manuell gesetzte Felder `metaTitle` und `metaDescription` werden durch automatisch generierte Inhalte ersetzt. Die Felder `metaTitleSetManually` und `metaDescriptionSetManually` werden dabei auf `false` gesetzt. Schreibrechte für SEO-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/texts/categories/reset ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ "cat1", "cat2" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von SEO-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig. | ## Methoden für Meta-Daten von Produkten Für Produkte steht ebenfalls nur eine Reset-Option zur Verfügung. Die API bietet keine Möglichkeit, einzelne SEO-Felder direkt zu aktualisieren. Stattdessen werden manuelle Meta-Angaben vollständig durch automatisch generierte Daten ersetzt. ### PUT seo/texts/products/reset Dieser Endpunkt löscht die manuell eingetragenen Meta-Daten von Produkten und ersetzt sie durch generierte Inhalte. Die Felder `metaTitleSetManually` und `metaDescriptionSetManually` werden dabei auf `false` gesetzt. Schreibrechte für SEO-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/texts/products/reset ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ "prod1", "prod2" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von SEO-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig. | ## Aktualisierung aller SEO-Texten Dieser Abschnitt beschreibt den Endpunkt zum manuellen Auslösen einer Aktualisierung aller SEO-Texte nach den konfigurierten Schemata. ### PUT seo/texts/update Dieser Endpunkt löst eine Aktualisierung aller SEO-Texte des Shops aus. Dabei werden Meta-Titel und Meta-Beschreibungen, die nicht manuell gesetzt wurden, anhand des konfigurierten Schemas neu generiert. Schreibrechte für SEO-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/texts/update ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von SEO-Daten. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Newsletter Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-newsletter Newsletter-Zielgruppen und Abonnentenlisten über die Admin Interface API auflisten, neu anlegen, aktualisieren sowie gezielt wieder entfernen. Der Endpunkt `newsletter/` stellt Ihnen eine Schnittstelle zur Verfügung mit der Sie Newsletter-Abonnenten und Newsletter-Zielgruppen verwalten können. Darüber können Sie Zielgruppen erstellen, aktualisieren und löschen. Es ist ebenfalls möglich, eine Liste mit allen Newsletter-Abonnenten abzurufen und neue Abonnenten anzulegen. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | --------------- | --------------------- | --------------------- | --------------------- | --------------------- | --------------------- | | **Zielgruppen** | newsletter/group | | | | | | **Abonnenten** | newsletter/subscriber | | | | | ## Datenfelder für Zielgruppen und Abonnenten Die Newsletter-Verwaltung unterscheidet zwei zentrale Entitäten: Zielgruppen und Abonnenten. Zielgruppen dienen der thematischen oder organisatorischen Einteilung von Abonnenten, etwa für gezielte Kampagnen oder regionale Segmente. Abonnenten sind einzelne Nutzer, die sich für einen Newsletter registriert haben und optional in mehreren Zielgruppen gleichzeitig geführt werden können. Die folgenden Tabellen beschreiben die jeweiligen Datenfelder: ### Datenfelder einer Zielgruppe | **Name** | **Typ** | **Verwendung** | | --------------- | ------- | ------------------------------------------------------------------------------------------------------- | | **id** | Integer | Eindeutiger Index der Zielgruppe | | **name** | String | Name der Zielgruppe | | **deactivated** | Boolean | Ist auf `false` gesetzt, wenn Abonnenten dieser Gruppe beitreten können. 1 = deaktiviert und 0 = aktiv. | | **createdAt** | String | Erstellungszeitpunkt (ISO 8601, UTC) | | **updatedAt** | String | Zeitpunkt der letzten Aktualisierung (ISO 8601-Format, UTC) | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2024-11-08T15:00:33.000Z", "deactivated": false, "id": 2, "name": "Zielgruppe 2", "updatedAt": "2025-01-21T15:08:55.000Z" } ``` ### Datenfelder eines Abonnenten | **Name** | **Typ** | **Verwendung** | | ------------------ | ------- | ------------------------------------------------------------------------------ | | **blacklisted** | Boolean | Gibt an, ob die E-Mail-Adresse auf einer Blacklist steht | | **createdAt** | String | Erstellungszeitpunkt (ISO 8601, UTC) | | **createdBy** | Integer | ID des Nutzers, der den Eintrag erstellt hat | | **email** | String | E-Mail-Adresse des Abonnenten | | **fields** | Objekt | JSON-Objekt mit zusätzlichen Registrierungsdaten wie Vorname, Nachname, Anrede | | **id** | Integer | Eindeutiger Index des Abonnenten | | **isImport** | Boolean | Gibt an, ob der Datensatz importiert wurde. | | **subshopId** | String | ID des Subshops, über den die Anmeldung erfolgte | | **targetGroupIds** | Array | Liste der Zielgruppen-IDs, denen der Abonnent zugeordnet ist | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "blacklisted": false, "createdAt": "2025-04-28T13:13:16.000Z", "createdBy": 0, "email": "m.mustermann@websale.de", "fields": { "firstName": "Max", "lastName": "Mustermann", "salutation": "1" }, "id": 1, "isImport": true, "subshopId": "deutsch", "targetGroupIds": [ 1 ] } ``` ## Methoden für Zielgruppen Die folgenden Methoden ermöglichen das Verwalten von Newsletter-Zielgruppen. Zielgruppen dienen der Segmentierung von Abonnenten innerhalb des Shopsystems. Über die API lassen sich bestehende Zielgruppen abrufen, bearbeiten, erstellen oder deaktivieren. Neue Abonnenten können nur aktiven Zielgruppen zugewiesen werden – eine Deaktivierung bedeutet, dass keine neuen Einträge mehr aufgenommen werden können. ### GET newsletter/group Mit dieser Methode wird eine Liste aller im System vorhandenen Zielgruppen geliefert. Optional kann die Ergebnisliste durch Filter auf den Status `deactivated` oder das Erstellungsdatum eingeschränkt werden. Eine Sortierung nach diesen Feldern ist ebenfalls möglich. Berechtigungen zum Lesen von Newsletter-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/newsletter/group ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "id": 1, "deactivated": false, "name": "Zielgruppe 1", "createdAt": "2024-11-07T11:04:35.000Z", "updatedAt": "2025-01-21T15:08:55.000Z" }, { "id": 2, "name": "Zielgruppe 2", "deactivated": false, "createdAt": "2024-11-08T15:00:33.000Z", "updatedAt": "2025-01-21T15:08:55.000Z" } ], "nextPageToken": "MQ", "totalCount": 2 } ``` #### Filterfelder `deactivated`, `createdAt` #### Sortierfelder `createdAt`, `updatedAt`, `name`, `id`, `deactivated` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Newslettern. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET newsletter/group/\{id} Diese Methode lädt die Details einer bestimmten Zielgruppe anhand ihrer ID. Zurückgegeben werden Informationen wie Name, Status, Erstellungs- und Aktualisierungsdatum. Berechtigungen zum Lesen von Newsletter-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/newsletter/group/2 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2024-11-08T15:00:33.000Z", "deactivated": false, "id": 2, "name": "Zielgruppe 2", "updatedAt": "2025-01-21T15:08:55.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Newslettern. | | 400 Bad Request | | `id` ist ungültig. | | 404 Not Found | | Zielgruppe mit `id`=`{id}` wurde nicht gefunden. | ### POST newsletter/group Eine neue Newsletter-Zielgruppe wird erstellt. Es muss ein Name angegeben werden, unbekannte Parameter führen zu einem Fehler. Nach erfolgreichem Erstellen wird der vollständige Eintrag mit Zeitstempeln und ID zurückgegeben. Erstellberechtigungen für Newsletter-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/newsletter/group ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "Exklusive Angebote" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": 3, "name": "Exklusive Angebote", "deactivated": false, "createdAt": "2025-05-01T12:00:00.000Z", "updatedAt": "2025-05-01T12:00:00.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Newslettern. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidFormat" | `name` ist kein String. | | 400 Bad Request | "missing" | `name` wurde nicht übergeben. | | 400 Bad Request | "unknownDataField" | Es wird versucht, ein unbekanntes Feld zu übergeben. Nur `name` ist erlaubt. | | 400 Bad Request | "duplicateEntry" | Eine Zielgruppe mit diesem `name` existiert bereits. | ### PUT newsletter/group/\{id} Diese Methode aktualisiert den Namen einer bestehenden Zielgruppe anhand ihrer ID. Unbekannte Parameter im Request-Body führen zu einem Fehler. Schreibberechtigungen für Newsletter-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/newsletter/group/2 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "newName" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": 2, "name": "newName", "deactivated": false, "createdAt": "2024-11-08T15:00:33.000Z", "updatedAt": "2025-01-21T15:08:55.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Newslettern. | | 400 Bad Request | | Request body konnte nicht geladen werden.
    `id` ist ungültig. | | 400 Bad Request | "invalidFormat" | Der Parameter `name` ist kein String. | | 400 Bad Request | "missing" | `name` wurde nicht übergeben. | | 400 Bad Request | "unknownDataField" | Es wird versucht, ein unbekanntes Feld zu übergeben. Nur `name` ist erlaubt. | | 404 Not Found | | Zielgruppe mit `id`=`{id}` wurde nicht gefunden. | ### DELETE newsletter/group/\{id} Eine Zielgruppe wird deaktiviert. Ab dem Zeitpunkt der Deaktivierung können keine neuen Abonnenten mehr dieser Gruppe beitreten. Bereits zugewiesene Abonnenten bleiben jedoch erhalten. Löschberechtigungen für Newsletter-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/newsletter/group/2 ``` #### Antwort Die Zielgruppe wird erfolgreich deaktiviert. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Newslettern. | | 400 Bad Request | | `id` ist ungültig. | | 404 Not Found | | Die Zielgruppe mit `id`=`{id}` wurde nicht gefunden. | ## Methoden für Abonnenten ### GET newsletter/subscriber Diese Methode liefert eine paginierte Liste aller Newsletter-Abonnenten im System. Die Abonnentendaten umfassen unter anderem die verschlüsselte E-Mail-Adresse, das Anmeldedatum sowie die persönlichen Informationen im Feld `fields`. Über Filter- und Sortierparameter lassen sich die Ergebnisse gezielt einschränken. Zum Zugriff sind entsprechende Leserechte für Newsletterdaten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/newsletter/subscriber ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "blacklisted": false, "createdAt": "2025-02-05T10:23:34.000Z", "createdBy": 1, "email": "m.mustermann@websale.de", "fields": { "firstName": "Max", "lastName": "Mustermann" }, "id": 43, "isImport": false, "subshopId": "", "targetGroupIds": [ 1, 2 ] } ], "nextPageToken": "NA", "totalCount": 1 } ``` #### Filterfelder `targetGroupIds`, `createdAt` #### Sortierfelder `id`, `createdAt` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Newslettern. | | 400 Bad Request | "invalidValue" | `size` ∉ \[1;300]
    `pageToken` ist keine Zahl oder kleiner als 0. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | | 503 Service Unavailable | | Interner Fehler beim Laden der Abonnentendaten. | ### GET newsletter/subscriber/\{id} Diese Methode lädt die vollständigen Daten eines einzelnen Newsletter-Abonnenten anhand seiner ID. Zusätzlich enthält die Antwort eine Historie aller Änderungen am Datensatz im Abschnitt `changes`, sofern diese vorhanden sind. Für die Nutzung dieser Methode sind entsprechende Leserechte für Newsletterdaten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/newsletter/subscriber/1 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "blacklisted": false, "changes": [ { "changes": { "fields.lastName": { "new": "Mustermann", "old": "Musterfrau" } }, "createdAt": "2025-02-05T10:28:48.000Z", "entryId": 43, "id": 12, "isImport": true, "userId": 1 } ], "createdAt": "2025-02-05T10:23:34.000Z", "createdBy": 1, "email": "m.mustermann@websale.de", "fields": { "firstName": "Max", "lastName": "Mustermann" }, "id": 43, "isImport": false, "subshopId": "", "targetGroupIds": [ 1, 2 ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Newslettern. | | 400 Bad Request | | `id` ist ungültig. | | 404 Not Found | | Abonnent mit `id`=`{id}` wurde nicht gefunden. | | 503 Service Unavailable | | Interner Fehler beim Laden des Abonnenten. | ### POST newsletter/subscriber/ Ein neuer Newsletter-Abonnent wird erstellt. Standardmäßig muss der Abonnent die Anmeldung bestätigen (Double-Opt-In). Da eine Bestätigung erforderlich ist, erscheint der Abonnent erst nach erfolgtem Opt-In in der Abonnentenliste. Für die Nutzung dieser Methode sind entsprechende Erstellrechte für Newsletterdaten erforderlich #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/newsletter/subscriber/ ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "m.mustermann@websale.de", "fields": { "firstName": "Max", "lastName": "Mustermann" }, "targetGroupIds": [ 1, 2 ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "blacklisted": false, "createdAt": "2025-02-05T10:23:34.000Z", "createdBy": 1, "email": "m.mustermann@websale.de", "fields": { "firstName": "Max", "lastName": "Mustermann" }, "id": 44, "isImport": false, "subshopId": "", "targetGroupIds": [ 1, 2 ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Newslettern. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidFormat" | `email` ist kein String oder hat kein gültiges E-Mail-Format, `fields` ist kein Objekt, `targetGroupIds` ist kein Array von Zahlen oder eines der Newsletterfelder hat gemäß den im Shop konfigurierten Überprüfungen einen ungültigen Wert. | | 400 Bad Request | "missing" | `email`, `fields` oder `targetGroupIds` wurde nicht übergeben, `targetGroupIds` ist ein leeres Array, oder eines der im Shop konfigurierten verpflichtenden Newsletterfelder ist nicht gesetzt. | | 400 Bad Request | "invalidValue" | `email` ist ein leerer String. | | 400 Bad Request | "unknownDataField" | Es wird versucht, ein unbekanntes Feld zu übergeben. Erlaubt sind nur `email`, `fields` und `targetGroupIds`. | | 503 Service Unavailable | | Der Double-Opt-In-Dienst ist nicht erreichbar. | ### PUT newsletter/subscriber/\{id} Diese Methode aktualisiert die Daten eines bestehenden Newsletter-Abonnenten anhand seiner ID. Dabei können ausschließlich die Felder `email`, `fields` (z. B. Vorname, Nachname) und `targetGroupIds` (Zielgruppen-Zugehörigkeit) verändert werden. Unbekannte Parameter im Request Body führen zu einem Fehler. Wenn die E-Mail-Adresse geändert wird, muss der Inhaber die Anmeldung erneut bestätigen. Solange es nicht geschehen ist, bleibt die Adresse unverändert. Für die Nutzung dieser Methode sind entsprechende Schreibrechte für Newsletterdaten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/newsletter/subscriber/1 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "fields": { "firstName": "Max", "lastName": "Mustermann" }, "targetGroupIds": [ 1, 2, 3 ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "blacklisted": false, "changes": [ { "changes": { "fields.firstName": { "new": "Max", "old": "Erika" }, "fields.lastName": { "new": "Mustermann", "old": "Musterfrau" }, "targetGroupIds": { "new": [ 1, 2, 3 ], "old": [ 1 ] } }, "createdAt": "2025-05-08T08:18:39.000Z", "entryId": 1, "id": 1, "isImport": false, "userId": 1 } ], "createdAt": "2025-02-05T10:23:34.000Z", "createdBy": 1, "email": "m.mustermann@websale.de", "fields": { "firstName": "Max", "lastName": "Mustermann" }, "id": 1, "isImport": false, "subshopId": "", "targetGroupIds": [ 1, 2, 3 ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Newslettern. | | 400 Bad Request | | Request body konnte nicht geladen werden.
    `id` ist ungültig. | | 400 Bad Request | "invalidFormat" | `email` ist kein String oder hat kein gültiges E-Mail-Format, `fields` ist kein Objekt, `targetGroupIds` ist kein Array von Zahlen oder eines der Newsletterfelder hat gemäß den im Shop konfigurierten Überprüfungen einen ungültigen Wert. | | 400 Bad Request | "missing" | `targetGroupIds` ist ein leeres Array, oder eines der im Shop konfigurierten verpflichtenden Newsletterfelder ist nicht gesetzt. | | 400 Bad Request | "invalidValue" | `email` ist ein leerer String. | | 400 Bad Request | "unknownDataField" | Es wird versucht, ein unbekanntes Feld zu übergeben. Erlaubt sind nur `email`, `fields` und `targetGroupIds`. | | 404 Not found | | Es existiert kein Abonnent mit `id={id}` | | 503 Service Unavailable | | Interner Fehler beim Laden des Abonnenten.
    Der Double-Opt-In-Dienst ist nicht erreichbar (nur bei Änderung der E-Mail-Adresse). | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz PayPal-Onboarding Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-paypal-onboarding PayPal-Onboarding-Vorgänge über die Admin Interface API anlegen, abrufen, aktualisieren, löschen sowie Action- und Return-URLs erzeugen. Der Endpunkt `payment/paypalonboarding` stellt eine REST-Schnittstelle bereit, um PayPal-Onboarding-Vorgänge im Shop-System zu verwalten. Er unterstützt das Anlegen, Abrufen, Aktualisieren und Löschen von Onboarding-Einträgen, das Erzeugen der für den Flow benötigten PayPal-Action-URL sowie die Verarbeitung des PayPal-Rücksprungs (Return-URL). *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | --------------------- | ------------------------ | --------------------- | --------------------- | --------------------- | --------------------- | | **PayPal-Onboarding** | payment/paypalonboarding | | | | | ## PayPal-Onboarding-Vorgang ### Datenfelder eines Eintrags | **Name** | **Typ** | **Verwendung** | | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **id** | String | Tracking-ID des Onboarding-Vorgangs; wird aus `__` generiert und dient als Primärschlüssel. | | **shop** | String | Shopkennung, der der Eintrag zugeordnet ist. | | **status** | Integer | Aktueller Onboarding-Status, abgeleitet u. a. aus E-Mail-Bestätigung, Zahlungsfähigkeit und Antwortvalidität.
    Mögliche Werte:
    `0` = Unknown (nicht bestimmt)
    `1` = NoConnection (keine gültige PayPal-Antwort/Verbindung)
    `2` = Success (Voraussetzungen erfüllt)
    `3` = EmailNotConfirmed (E-Mail nicht bestätigt)
    `4` = PaymentNotReceivable (Konto kann (noch) keine Zahlungen empfangen)
    `5` = InvalidResponse (unvollständige/unerwartete Antwort) | | **merchantId** | String | Händler-ID bei PayPal (`merchantIdInPayPal`); identifiziert das PayPal-Konto eindeutig. | | **email** | String | Primäre PayPal-E-Mail des Händlerkontos (`primary_email`). | | **permissionsGranted** | Boolean | Gibt an, ob die nötigen OAuth-Berechtigungen/Scopes gewährt wurden (Return-Param `permissionGranted` bzw. aus PayPal-Status). | | **emailConfirmed** | Boolean | Gibt an, ob die primäre E-Mail bei PayPal bestätigt ist (`primary_email_confirmed`). | | **consentStatus** | Boolean | Gibt an, ob rechtliche Einwilligungen erteilt wurden (Return-Param `consentStatus`). | | **accountType** | String | Vom PayPal-Rücksprung gemeldeter Kontozustand. | | **updatedAt** | String | Zeit der letzten Aktualisierung des Eintrags (ISO 8601-Format, UTC). | | **createdAt** | String | Zeitpunkt der Erstellung (ISO 8601-Format, UTC). | | **deletedAt** | String | Zeitpunkt der Löschung (ISO 8601-Format, UTC); leer, wenn der Eintrag aktiv ist. | | **rawResponse** | String | Vollständige, ungefilterte Antwort der PayPal-Account-Status-API (als JSON-String) zur Nachverfolgung/Debugging. | | **activePayments** | String | Freigegebene Zahlungsarten. | | **mode** | Integer | Betriebsmodus des Eintrags (aus Konfiguration ermittelt): Produktion oder Test.
    Mögliche Werte:
    `0` = Unknown
    `1` = Production
    `2` = Test | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountType": "", "activePayments": "", "consentStatus": false, "createdAt": "2025-09-15T09:42:35Z", "deletedAt": "", "email": "", "emailConfirmed": false, "id": "1757929355_myshop_8", "merchantId": "", "mode": 2, "permissionsGranted": false, "rawResponse": "", "shop": "myshop", "status": 1, "updatedAt": "2025-09-15T09:42:35Z" } ``` ## Methoden für PayPal-Onboarding Dieser Abschnitt beschreibt die Endpunkte zur Verwaltung einzelner PayPal-Onboarding-Einträge. ### GET payment/paypalonboarding Mit diesem Endpunkt kann eine Liste der vorhandenen Onboarding-Einträge des aktuellen Shops geladen werden. Dabei werden Such- und Filterparameter aus der Anfrage berücksichtigt und auf `deleted=false` begrenzt. Enthält die Anfrage den Hinweis auf einen PayPal-Rücksprung (`PPact=finish`), [werden zuerst die Rücksprungdaten verarbeitet](/schnittstellen/admin-interface-api/api-referenz-paypal-onboarding). Für die Nutzung sind Leseberechtigungen für PayPal-Onboarding-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/payment/paypalonboarding?size=100 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "accountType": "", "activePayments": "", "consentStatus": false, "createdAt": "2025-09-12T06:54:33Z", "deletedAt": "", "email": "", "emailConfirmed": false, "id": "1757660073_myshop_1", "merchantId": "", "mode": 2, "permissionsGranted": false, "rawResponse": "", "shop": "myshop", "status": 1, "updatedAt": "2025-09-12T06:54:33Z" }, { "accountType": "", "activePayments": "", "consentStatus": false, "createdAt": "2025-09-15T08:43:26Z", "deletedAt": "", "email": "", "emailConfirmed": false, "id": "1757925806_myshop_2", "merchantId": "", "mode": 2, "permissionsGranted": false, "rawResponse": "", "shop": "myshop", "status": 1, "updatedAt": "2025-09-15T08:43:26Z" } ], "nextPageToken": "MQ", "totalCount": 2 } ``` #### Filterfelder `id`, `updatedAt`, `status`, `emailConfirmed`, `permissionsGranted`, `mode`, `deleted` #### Sortierfelder `updatedAt`, `createdAt`, `id`, `shop`, `merchantId`, `accountType`, `status`, `mode`, `emailConfirmed`, `email`, `consentStatus`, `permissionsGranted` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von PayPal-Onboarding-Daten. | | 400 Bad Request | "invalidValue" | `size` ∉ \[1;300]
    `pageToken` ist keine Zahl oder kleiner als 0.
    Die Sortierrichtung in `sort` ist nicht "asc" oder "desc". | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | | 503 Service Unavailable | "internalError" | Das Lesen von Daten ist fehlgeschlagen. | ### GET payment/paypalonboarding/\{id} Mit diesem Endpunkt kann ein einzelner Onboarding-Eintrag anhand seiner ID für den aktuellen Shop abgerufen werden. Für die Nutzung dieses Endpunkts sind Leseberechtigungen für PayPal-Onboarding-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/payment/paypalonboarding/1757660073_myshop_1 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountType": "", "activePayments": "", "consentStatus": false, "createdAt": "2025-09-12T06:54:33Z", "deletedAt": "", "email": "", "emailConfirmed": false, "id": "1757660073_myshop_1", "merchantId": "", "mode": 2, "permissionsGranted": false, "rawResponse": "", "shop": "myshop", "status": 1, "updatedAt": "2025-09-12T06:54:33Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ---------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von PayPal-Onboarding-Daten. | | 404 Not Found | | Die Daten wurden nicht gefunden. | ### GET payment/paypalonboarding/\{id}/url Mit diesem Endpunkt kann die aktuelle PayPal-Action-URL zu einer Tracking-ID direkt angefordert werden. Die URL ist für den Einstieg in den PayPal-Onboarding-Flow bestimmt und enthält die konfigurierte Return-URL des Shops. Für die Nutzung dieses Endpunkts sind Schreibberechtigungen für PayPal-Onboarding-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/payment/paypalonboarding/1757925806_myshop_2/url ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "action_url": "https://www.sandbox.paypal.com/bizsignup/partner/entry?referralToken=NjlhMjM3ODctMDZjMy00MjZkLWJjMGQtMTU1YzdiZjRiMjQwMm5xRk9weFNtYjNDRmpYb2g3b25RdzVqeWtacEVCSnVTZzRaL3NsMkdXRT12Mg==" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | -------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von PayPal-Onboarding-Daten. | | 404 Not Found | | Die URL konnte nicht generiert werden. Details sind in Logs zu finden. | ### POST payment/paypalonboarding Mit diesem Endpunkt kann ein neuer Onboarding-Eintrag angelegt werden. Die Tracking-ID wird aus Zeitstempel, Shop-ID und einer fortlaufenden Nummer gebildet; der Betriebsmodus (Production/Test) wird aus der Konfiguration ermittelt. Als Ergebnis wird die erzeugte `{ "trackingId": "…" }` zurückgegeben. Für die Nutzung dieses Endpunkts sind Erstellberechtigungen für PayPal-Onboarding-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/payment/paypalonboarding ``` #### Request Body ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "trackingId": "1757929355_myshop_8" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von PayPal-Onboarding-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden.
    In der `setupConfig` wurde kein Modus angegeben. Mögliche Werte: `"production"`, `"test"`
    Das Anlegen von Daten ist fehlgeschlagen. | | 404 Not Found | | Die Daten konnten nach dem Anlegen nicht geladen werden. | ### PUT payment/paypalonboarding/\{id} Mit diesem Endpunkt kann ein Onboarding-Eintrag aktualisiert oder – falls noch keine Händler-ID vorliegt – die PayPal-Action-URL für den Start des Onboardings abgefragt werden. Ohne `merchantIdInPayPal` liefert der Endpunkt die Aktions-URL (`{ "acturl": "…" }`). Mit `merchantIdInPayPal` wird der Konto-/Integrationsstatus bei PayPal abgefragt, relevante Felder (z. B. E-Mail-Bestätigung, Zahlungsfähigkeit, Scopes) werden übernommen und ein entsprechender interner Status gesetzt; das Ergebnis ist der aktualisierte Eintrag als JSON. Für die Nutzung dieses Endpunkts sind Schreibberechtigungen für PayPal-Onboarding-Daten erforderlich. #### Query-Parameter `merchantIdInPayPal` – (optional) PayPal-Merchant-ID. Wenn angegeben, wird der Account-Status bei PayPal abgefragt und der Eintrag aktualisiert. Wenn nicht angegeben, wird stattdessen die Aktions-URL zurückgegeben. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/payment/paypalonboarding/1757927249_myshop_6 ``` #### Antwort, wenn keine `merchantIdInPayPal` übergeben wurde ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "acturl": "https://www.sandbox.paypal.com/bizsignup/partner/entry?referralToken=YjY3Nzk2ODQtYTQwOS00MjhiLWFhYWUtMzc1YjcyOTMwZmViVkN0MXA2RlFxTDhZTnRxWGxnL0s4Mmpick5udERFUmNFZ3NJZVlmNDZpUT12Mg==" } ``` #### Antwort, wenn eine `merchantIdInPayPal` übergeben wurde ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountType": "BUSINESS", "activePayments": "", "consentStatus": true, "createdAt": "2025-09-15T09:07:29Z", "deletedAt": "", "email": "merchant@example.com", "emailConfirmed": true, "id": "1757927249_myshop_6", "merchantId": "ABCDEF123456", "mode": 2, "permissionsGranted": true, "rawResponse": "{...}", "shop": "myshop", "status": 2, "updatedAt": "2025-09-15T10:15:00Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | -------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von PayPal-Onboarding-Daten. | | 400 Bad Request | | Das Aktualisieren von Daten ist fehlgeschlagen. | | 404 Not Found | | Die Aktions-URL konnte nicht ermittelt werden oder PayPal hat keine Account-Daten geliefert. | ### PUT payment/paypalonboarding/\{id}/checkstatus Mit diesem Endpunkt werden Rücksprungdaten von PayPal (Return-URL) entgegengenommen, protokolliert und dem zugehörigen Onboarding-Eintrag zugeordnet. Die gelieferten Query-Parameter werden gespeichert; anschließend wird der gültige Account-Status über die PayPal-API abgefragt, im Eintrag persistiert und der aktualisierte Eintrag als JSON zurückgegeben. Für die Nutzung dieses Endpunkts sind Schreibberechtigungen für PayPal-Onboarding-Daten erforderlich. #### Query-Parameter `commonid` – Shop-ID\ `merchantId` – Tracking-ID des Eintrags\ `merchantIdInPayPal` – PayPal-Merchant-ID\ `accountStatus` – Kontostatus\ `consentStatus` – Zustimmungsstatus ("true"/"false")\ `isEmailConfirmed` – E-Mail bestätigt ("true"/"false")\ `permissionGranted` – Berechtigungen erteilt ("true"/"false") #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/payment/paypalonboarding/1757927249_myshop_6/checkstatus?commonid=myshop&merchantId=1757927249_myshop_6&merchantIdInPayPal=ABCDEF123456&accountStatus=BUSINESS&consentStatus=true&isEmailConfirmed=true&permissionGranted=true ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountType": "BUSINESS", "activePayments": "", "consentStatus": true, "createdAt": "", "deletedAt": "", "email": "", "emailConfirmed": false, "id": "1757927249_myshop_6", "merchantId": "ABCDEF123456", "mode": 0, "permissionsGranted": true, "rawResponse": "{...}", "shop": "myshop", "status": 5, "updatedAt": "" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | -------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von PayPal-Onboarding-Daten. | | 400 Bad Request | | Das Aktualisieren von Daten ist fehlgeschlagen. | | 404 Not Found | | PayPal hat keine Daten geliefert. | ### DELETE payment/paypalonboarding/\{id} Mit diesem Endpunkt wird ein vorhandenes Onboarding-Eintrag anhand seiner ID als gelöscht markiert (Soft-Delete). Der Eintrag verbleibt in der Datenbank, wird jedoch mit einem Löschzeitstempel versehen und erscheint nicht mehr in der Liste. Die Anfrage liefert die aktualisierte Liste im Response Body zurück. Für die Nutzung dieses Endpunkts sind Löschberechtigungen für PayPal-Onboarding-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/payment/paypalonboarding/1757929355_myshop_8 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "accountType": "", "activePayments": "", "consentStatus": false, "createdAt": "2025-09-12T06:54:33Z", "deletedAt": "", "email": "", "emailConfirmed": false, "id": "1757660073_myshop_1", "merchantId": "", "mode": 2, "permissionsGranted": false, "rawResponse": "", "shop": "myshop", "status": 1, "updatedAt": "2025-09-12T06:54:33Z" }, ... ], "nextPageToken": "Ng", "totalCount": 7 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von PayPal-Onboarding-Daten. | | 404 Not Found | | Es wurden keine Daten gefunden. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Produktbewertungen Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-produktbewertungen Produktbewertungen über die Admin Interface API abrufen, filtern, bearbeiten und löschen sowie ihren Freigabestatus im Shop verwalten. Der Endpunkt `/productRating` stellt Ihnen eine Schnittstelle bereit um Produktbewertungen in unserem Shopsystem, zu verwalten. Sie können Produktbewertungen abrufen, aktualisieren, filtern und löschen. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | ------------------------- | -------------- | --------------------- | ------------------- | --------------------- | --------------------- | | **Allgemeines Bewertung** | productRating/ | | | | | ## Datenfelder Bewertungen (Rating Resource) Bewertungen sind in einer Datenbanktabelle gespeichert. Es gibt eine weitere Tabelle für Durchschnittswerte und die Anzahl der Bewertungen eines Produkts. Diese Tabelle wird automatisch aktualisiert, und ihre Werte werden gelesen, wenn man eine einzelne Bewertung abfragt. | Name | Typ | Bedeutung | | ------------------ | ------- | ------------------------------------------------------------------------------ | | accountId | String | ID des Kundenkontos, das die Bewertung abgegeben hat | | accountType | Integer | Typ des Kundenkontos (z. B. Gast (`1`) oder registrierter Kunde (`3`)) | | anonymous | Boolean | `True` = Bewertung wurde anonym abgegeben, `False` = mit Kundenkonto verknüpft | | answeredAt | String | Zeitpunkt der Händlerantwort (ISO 8601-Format, UTC) | | approval | Boolean | Gibt an, ob die Bewertung freigegeben wurde | | categoryId | String | Kategorie, der das bewertete Produkt zugeordnet ist | | createdAt | String | Zeitpunkt der Erstellung der Bewertung (ISO 8601-Format, UTC) | | description | String | Ausführliche Beschreibung bzw. Text der Bewertung | | disapprovalReason | String | Grund für die Ablehnung der Bewertung (falls abgelehnt) | | id | Integer | Eindeutige ID der Bewertung | | merchantComment | String | Antwort oder Kommentar des Händlers zur Bewertung | | orderId | String | ID der Bestellung, mit der das Produkt gekauft wurde | | points | Number | Vergebene Punktzahl, z. B. im Bereich 1–5 | | productId | String | Technische ID des bewerteten Produkts | | productName | String | Aktueller Name des Produkts | | productNumber | String | Artikelnummer des Produkts | | productType | String | Produkttyp (z. B. `standard`, `digital`) | | subject | String | Betreff oder Titel der Bewertung | | subshopId | String | Subshop, in dem die Bewertung abgegeben wurde | | averageRating | Number | Durchschnittliche Bewertungspunktzahl des Produkts | | totalRating | Integer | Gesamtanzahl der Bewertungen des Produkts | | variationSelection | Array | Ausgewählte Produktvarianten aus der zugehörigen Bestellung | | orderSubshop | String | Subshop der zugehörigen Bestellung | #### Beispiel von einem Datensatz ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountId": "1", "accountType": 0, "anonymous": false, "answeredAt": "2024-12-16 14:14:43", "approval": false, "categoryId": "911-78497", "createdAt": "2024-09-27 13:26:10", "description": "Meaningful description", "disapprovalReason": "You shall not pass", "id": 3, "merchantComment": "", "orderId": "233", "points": 2, "productId": "440-35068", "productName": "Regular product", "productNumber": "123456", "productType": "standard", "subject": "I do not like it", "subshopId": "deutsch" } ``` ## Verwendung der Methoden ### GET productRating Zugriff auf Bewertungen mit Filtermöglichkeiten. #### Beispiel Zugriff auf bis zu 100 nicht freigegebenen Bewertungen im Zeiraum 2024.12.02–2025.01.06. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/productRating?size=100&filter_gte[createdAt]=2024-12-02T00:00:00.000Z &filter_lte[createdAt]=2025-01-05T23:59:59.000Z&filter_eq[approval]=false ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "accountId": "1", "accountType": 0, "anonymous": false, "answeredAt": "", "approval": false, "categoryId": "911-78497", "createdAt": "2024-09-27 13:26:10", "description": "Meaningful description", "disapprovalReason": "You shall not pass", "id": 3, "merchantComment": "", "orderId": "233", "points": 2, "productId": "440-35068", "productType": "standard", "subject": "I do not like it", "subshopId": "deutsch", "productName": "Regular product", "productNumber": "123456" } ], "nextPageToken": "MQ", "totalCount": 2 } ``` #### Filterfelder `id`, `productId`, `accountId`, `orderId`, `points`, `approval`, `createdAt`, `answeredAt`, `subject`, `disapprovalReason`, `anonymous`, `subshopId` #### Sortierfelder `createdAt`, `answeredAt`, `id`, `productId`, `accountId`, `orderId`, `points`, `approval`, `anonymous`, `subject`, `description`, `merchantComment`, `disapprovalReason`, `subshopId` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Bewertungen. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl. | ### GET productRating/\{id} Zugriff auf eine bestimmte Bewertung. Es steht auch in der Antwort, wie oft das korrespondierende Produkt bewertet wurde und was der Durchschnittswert ist. Wenn eine Variante ausgewählt wurde, wird das auch mitgeteilt. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/productRating/123 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountId": "1", "accountType": 0, "anonymous": false, "answeredAt": "2025-01-16 11:33:52", "approval": true, "categoryId": "911-78497", "createdAt": "2024-12-18 22:35:24", "description": "I recomend it", "disapprovalReason": "", "id": 2, "merchantComment": "Thanks!", "orderId": "233", "points": 4, "productId": "105-59442", "productType": "standard", "subject": "Good product", "subshopId": "deutsch", "averageRating": 4.0, "totalRating": 1, "variationSelection": [], "orderSubshop": "deutsch" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ----------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Bewertungen. | | 404 Not Found | | Bewertungsstatistiken oder die korrespondierende Bestellung konnten nicht geladen werden. | | 503 Service Unavailable | "internalError" | Die Bewertung konnte nicht gelesen werden. | ### PUT productRating/\{id} Die Bewertung mit der angegebenen Id wird aktualisiert. Nur die im Beispiel gezeigte Felder können verändert werden. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/productRating/123 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "approval": false, "merchantComment": "", "disapprovalReason": "Bad rating" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountId": "1", "accountType": 0, "anonymous": false, "answeredAt": "2025-01-16 11:33:52", "approval": false, "categoryId": "911-78497", "createdAt": "2024-12-18 22:35:24", "description": "Dislike!", "disapprovalReason": "Bad rating", "id": 2, "merchantComment": "", "orderId": "233", "points": 1, "productId": "105-59442", "productType": "standard", "subject": "Dislike", "subshopId": "deutsch", "averageRating": 4.0, "totalRating": 1, "variationSelection": [], "orderSubshop": "deutsch" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Bewertungen. | | 404 Not Found | | Die Bewertung wurde nicht gefunden.
    Bewertungsstatistiken oder die korrespondierende Bestellung konnten nach dem Update nicht geladen werden. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidFormat" | `merchantComment` oder `disapprovalReason` sind keine Strings.
    `approval` ist kein Boolean. | | 400 Bad Request | "unknownDataField" | Man aktualisiert ein Feld, das nicht aktualisiert werden darf. | | 503 Service Unavailable | "internalError" | Das Aktualisieren ist fehlgeschlagen. | ### DELETE productRating/\{id} Die Bewertung mit der angegebenen Id wird gelöscht. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/productRating/123 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Bewertungen. | | 404 Not Found | | Die Bewertung wurde nicht gefunden. | | 503 Service Unavailable | "internalError" | Das Löschen ist fehlgeschlagen. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Produkte Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-produkte Produkte, Varianten, zeitgesteuerte Preise und Lagerbestände über die Admin Interface API anlegen, abrufen, aktualisieren, löschen sowie Bulk-Operationen ausführen. Der Endpunkt `/products` stellt Ihnen eine Schnittstelle bereit, mit der Sie Produktdaten und Lagerbestände in unserem Shop-System verwalten können. Darüber können Sie Produkte erstellen, bearbeiten, filtern, abrufen und löschen sowie Lagerbestandsinformationen zu Produkten abrufen, aktualisieren und löschen. ## Unterstützte Methoden | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | ------------------------------ | ----------------------------------------------------- | --------------------- | --------------------- | --------------------- | --------------------- | | **Allgemeines Produkt** | products/ | | | | | | **Allgemeines Produkt (Bulk)** | bulk/products | | | | | | **Variantenattribute** | products/variants | | | | | | **Varianten** | products/\{productId}/variants | | | | | | **Varianten (Bulk)** | bulk/products/variants | | | | | | **Lagerbestand Allgemein** | products/inventory | | | | | | **Lagerbestand für Produkte** | products/\{productId}/inventory | | | | | | **Lagerbestand für Varianten** | products/\{productId}/variants/\{variantId}/inventory | | | | | | **Lagerbestand (Bulk)** | bulk/products/inventory | | | | | | **Set-Produkte** | products/\{parentProductId}/setproducts | | | | | ## Datenfelder Felder werden in der Konfiguration verwaltet und als ein JSON-Objekt in der Tabelle gespeichert. Es wird unterschieden zwischen Standardproduktdatenfeldern und benutzerdefinierten Produktdatenfeldern. Benutzerdefinierte Produktdatenfelder können beliebig angelegt werden, während Standardproduktdatenfelder vom Shop vorgegeben werden und immer definiert sind. Alle benutzerdefinierte Produktdatenfelder sind im Abschnitt custom zu finden. Alle anderen Einträge stellen Standardproduktdatenfelder dar. | **Name** | **Typ** | **Bedeutung** | | -------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **active** | String | Aktivitätsstatus des Produkts (beispielsweise „always“, „never“) | | **custom** | Objekt | Benutzerdefinierte Felder | | **custom.liste** | Array | Beispielhafte Liste | | [**custom.map**](http://custom.map) | Objekt | Beispielhafte Schlüssel-Wert-Zuordnungen | | **custom.validInsertCodes** | Array | Liste der für dieses Produkt gültigen [Werbemittelkennzeichen](/frontend/funktionsubersicht/werbemittelkennzeichnung). Jeder Eintrag maximal 16 Zeichen. Nur wirksam, wenn das Feld in `content.usedFields.products.validInsertCodes` zugeordnet und die Werbemittelkennzeichnung aktiv ist. | | **custom.robotsNoFollow** | Boolean | True = Link zu diesem Produkt sollte von Suchmaschinen nicht gefolgt werden | | **custom.robotsNoIndex** | Boolean | True = Produktseite sollte nicht in Suchmaschinen indiziert werden | | **custom.weight** | Float | Gewicht des Produkts in Kilogramm (zur Priorisierung oder Sortierung) | | **descr** | String | Produktbeschreibung | | **hasVariants** | Boolean | Gibt an, ob das Produkt Varianten besitzt (beispielsweise Größe, Farbe) | | **id** | String | Technische ID des Produkts | | **itemNumber** | String | Artikelnummer (kann identisch mit `id` sein) | | **name** | String | Klartext-Name des Produkts | | **price** | Objekt | Standardpreis des Produkts und dessen geplante Aktionspreise. Den Aufbau beschreibt der Abschnitt [Zeitgesteuerte Preise (Aktionspreise)](#zeitgesteuerte-preise-aktionspreise). | | **ratingApprovalConfig.maximumRating** | Integer | Maximal zulässige Bewertung (beispielsweise 5) | | **ratingApprovalConfig.minimumRating** | Integer | Minimal zulässige Bewertung (beispielsweise 0) | | **statistics.averageRating** | Float | Durchschnittliche Bewertung des Produkts | | **statistics.ratingCount** | Integer | Anzahl der abgegebenen Bewertungen | | **statisticsPerPoint** | Array | Bewertungshistogramm: für jeden möglichen Wert Anzahl Bewertungen | | **taxRateId** | String | ID des angewendeten Steuersatzes | | **timestampCreatedAt** | String | Zeitpunkt der Erstellung (ISO 8601-Format, UTC) | | **timestampUpdatedAt** | String | Zeitpunkt der letzten Produktänderung (ISO 8601-Format, UTC) | #### Beispielhafter Datensatz ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": "always", "custom": { "liste": [ "123", "234", "456" ], "map": { "a": "b", "c": "d", "e": "f" }, "robotsNoFollow": false, "robotsNoIndex": false, "weight": 0.33 }, "descr": "Lässiges Barbour-Shirt aus Baumwoll-Piqué mit Langarm. Gearbeitet in gerader, normaler Passform (Regular Fit) mit Kontrastbesatz im 'Barbour-Tartan' an der Knopfleiste und im Kragen. Mit klassischem Polokragen, Ärmelbündchen und gesticktem Barbour-Logo. Ein Mode-Klassiker für die Freizeit, in dem sich jeder Mann wohlfühlt. Länge ca. 75 cm.Farbe: Navy. Original Barbour. Größen: M (48), L (50), XL (52/54), XXL (56/58), XXXL (58/60) Reine Baumwolle.", "hasVariants": true, "id": "11-1701", "itemNumber": "11-1701", "name": "Tartan-Langarm-Polo in Navy", "price": { "price": "89.900000", "scheduledPrices": [] }, "ratingApprovalConfig": { "maximumRating": 5, "minimumRating": 0 }, "statistics": { "averageRating": 0, "ratingCount": 0 }, "taxRateId": "1", "statisticsPerPoint": [ [ 0, 0 ], [ 1, 0 ], [ 2, 0 ], [ 3, 0 ], [ 4, 0 ], [ 5, 0 ] ], "timestampCreatedAt": "2024-11-14T10:41:25.000Z", "timestampUpdatedAt": "2025-01-24T09:28:06.000Z" } ``` ## Zeitgesteuerte Preise (Aktionspreise) Produkte können Preise mit einem Gültigkeitszeitraum tragen. Damit lassen sich Aktionspreise im Voraus pflegen, ohne dass zum Aktionsstart ein Import oder eine manuelle Änderung nötig ist. Dieser Abschnitt beschreibt zuerst das Format der Preisfelder in Antworten, danach das erlaubte Format in Requests, anschließend die Wirkung im Shop und zuletzt die Validierung. Wer nur wissen will, was an bestehenden Anbindungen anzupassen ist, findet die kurze Antwort im folgenden Hinweis. **Breaking Change in Antworten.** Jedes Feld vom Typ `Price` wird in Produkt-Antworten nicht mehr als String, sondern als Objekt ausgeliefert. Betroffen sind das Basisfeld `price` und alle benutzerdefinierten Preisfelder. Anbindungen, die den Preis direkt als String weiterverarbeiten, müssen angepasst werden. Die Änderung betrifft alle Endpunkte, die Produktdaten ausliefern, also die Abfrage einzelner Produkte, Listenabfragen, die Antworten von Erstellen und Aktualisieren sowie die Bulk-Endpunkte. ### Preisfelder in Antworten Ein Preisfeld enthält den Standardpreis und die Liste der geplanten Aktionspreise. Die Liste `scheduledPrices` ist immer vorhanden. Sind keine Aktionspreise gepflegt, wird sie als leeres Array ausgeliefert. #### Antwort (Auszug) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "price": { "price": "19.990000", "scheduledPrices": [ { "price": "14.990000", "startDate": "2026-08-01T00:00:00.000Z", "endDate": "2026-08-31T23:59:59.000Z", "promotionInfo": "Sommeraktion", "validForDiscount": true } ] } } ``` Vor dieser Änderung stand an derselben Stelle ein reiner String: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "price": "19.990000" } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------------------------------ | ---------------- | --------------------------------------------------------------------------------------------------------------------------------- | | `price` | `string` | Standardpreis des Feldes. Er gilt immer dann, wenn kein Aktionspreis aktiv ist. | | `scheduledPrices` | `array` (object) | Liste der geplanten Aktionspreise. Leeres Array, wenn keine gepflegt sind. | | `scheduledPrices[].price` | `string` | Aktionspreis für diesen Zeitraum. Pflichtangabe und größer als `0`. | | `scheduledPrices[].startDate` | `string` | Beginn des Zeitraums im Format ISO 8601 (UTC). Ein leerer String bedeutet offener Beginn, der Eintrag gilt also von Anfang an. | | `scheduledPrices[].endDate` | `string` | Ende des Zeitraums im Format ISO 8601 (UTC). Ein leerer String bedeutet offenes Ende, der Eintrag gilt also unbefristet. | | `scheduledPrices[].promotionInfo` | `string` | Freier Text zur Aktion, beispielsweise für eine Kennzeichnung im Shop. Das Feld fehlt in der Antwort, wenn kein Text gesetzt ist. | | `scheduledPrices[].validForDiscount` | `bool` | Gibt an, ob während des Aktionszeitraums weitere Rabatte auf den Preis gewährt werden. Standardwert `true`. | Der Zeitraum ist an beiden Enden einschließend. Ein Eintrag mit `endDate` auf `2026-08-31T23:59:59.000Z` ist zu genau dieser Sekunde noch aktiv. Bei Produktvarianten kann ein Preisfeld auch `null` sein. Der Typ eines Preisfelds ist für Anbindungen deshalb `object | null`. Wann dieser Fall auftritt, beschreibt der Abschnitt [Methoden für Produktvarianten](#methoden-für-produktvarianten). ### Preisfelder in Requests Eingehend bleibt die Schnittstelle abwärtskompatibel. Ein Preisfeld darf weiterhin als reiner String übergeben werden. Bestehende Schreibzugriffe funktionieren damit unverändert weiter. Angepasst werden muss nur, wer Aktionspreise über die Schnittstelle pflegen will. Alternativ nimmt die Schnittstelle das Objekt in derselben Struktur an, in der sie es ausliefert. Wird das Feld `scheduledPrices` nicht mitgeschickt, bleiben bestehende Einträge erhalten. Ein leer übergebenes Array löscht alle Einträge. #### Request Body (Auszug) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "price": { "price": "19.99", "scheduledPrices": [ { "price": "14.99", "startDate": "2026-08-01T00:00:00.000Z", "endDate": "2026-08-31T23:59:59.000Z", "promotionInfo": "Sommeraktion", "validForDiscount": true } ] } } ``` ### Wirkung im Shop Zu jedem Zeitpunkt wird genau ein Preis aufgelöst. Die Auflösung geschieht bei jeder Anfrage neu, es wird also kein Preis vorberechnet und gespeichert. Welcher Preis gilt, entscheiden drei Regeln. Erstens greift ein Aktionspreis nur dann, wenn er den Standardpreis nicht überschreitet. Einträge über dem Standardpreis werden bei der Auflösung übersprungen. In diesem Fall bleibt der Standardpreis gültig. Zweitens wird bei mehreren gleichzeitig aktiven Einträgen der niedrigste Preis verwendet. Bei gleichem Preis gewinnt der Eintrag mit dem späteren `startDate`, ein offener Beginn verliert also. Sind auch die Startzeitpunkte gleich, entscheidet die Reihenfolge im Array. Drittens ersetzt ein eigenes Preisfeld an einer Variante den Standardpreis und den Zeitplan des Basisprodukts gemeinsam. Mehr dazu im Abschnitt [Methoden für Produktvarianten](#methoden-für-produktvarianten). Die Validierung prüft einen Aktionspreis nicht gegen den Standardpreis. Ein Eintrag über dem Standardpreis wird gespeichert und in der Antwort wieder ausgeliefert, er greift aber nie. Das wirkt auch nachträglich. Wird der Standardpreis später unter einen bestehenden Aktionspreis gesenkt, verliert dieser Eintrag stillschweigend seine Wirkung. Für den Suchindex gilt eine Einschränkung. Preisfelder werden ausschließlich mit ihrem Standardpreis indexiert. Geplante Aktionspreise stehen im Index nicht zur Verfügung und können deshalb nicht gefiltert oder sortiert werden. ### Validierung und Fehlerschlüssel Jeder Eintrag wird einzeln geprüft. Fehlerhafte Angaben führen zu `400 Bad Request`. Der Fehlerschlüssel enthält den Index des betroffenen Eintrags im Array. | **Fehlerschlüssel** | **Typ** | **Grund** | | --------------------------------------- | --------------- | -------------------------------------------- | | `.scheduledPrices[]` | "invalidFormat" | Der Eintrag ist kein Objekt. | | `.scheduledPrices[].price` | "missing" | `price` fehlt oder ist leer. | | `.scheduledPrices[].price` | "invalidFormat" | `price` kann nicht als Preis geparst werden. | | `.scheduledPrices[].price` | "invalidValue" | `price` ist kleiner oder gleich `0`. | | `.scheduledPrices[].startDate` | "invalidFormat" | `startDate` ist nicht im Format ISO 8601. | | `.scheduledPrices[].endDate` | "invalidFormat" | `endDate` ist nicht im Format ISO 8601. | | `.scheduledPrices[].endDate` | "invalidValue" | `startDate` liegt nach `endDate`. | Geprüft wird ausschließlich der Eintrag selbst. Ein Vergleich mit dem Standardpreis oder mit anderen Einträgen findet nicht statt. Überlappende Zeiträume und Preise über dem Standardpreis führen deshalb nicht zu einem Fehler, sondern wirken sich erst bei der Auflösung aus. Welcher Eintrag dann greift, beschreibt der Abschnitt [Wirkung im Shop](#wirkung-im-shop). ### Hinweis zum internen Speicherformat Für Werkzeuge, die direkt auf dem gespeicherten Datenblob eines Produkts oder einer Kategorie arbeiten, gilt eine Besonderheit. Dort tragen die beiden Wrapper eine andere Bezeichnung als im REST-Vertrag. Die inneren Schlüssel eines Eintrags sind identisch. | **Bedeutung** | **REST-Vertrag** | **Gespeicherter `data`-Blob** | | ------------- | ----------------- | ----------------------------- | | Standardpreis | `price` | `standard` | | Zeitplan | `scheduledPrices` | `schedule` | Beide Lesepfade akzeptieren zusätzlich das alte Format als reinen String. Bestandsdaten müssen dafür nicht migriert werden. ## Methoden für Produkte Die hier dokumentierten Endpunkte ermöglichen den Lese-, Schreib-, Änderungs- und Löschzugriff auf Produktdaten im Shopsystem. Sie können zur Verwaltung des Produktkatalogs genutzt werden, sowohl zur Initialbefüllung als auch zur laufenden Aktualisierung von Inhalten. Zusätzlich stehen Endpunkte zur Verfügung, um Produktsuchen auf Basis definierter Regeln durchzuführen. Da jeder Subshop eine eigene Produktmenge hat, sollen URLs den Parameter `subshopId` enthalten. Für alle Endpunkte ist eine gültige Authentifizierung erforderlich. Die jeweiligen Berechtigungen zum Lesen, Schreiben, Erstellen oder Löschen von Produkten müssen vorhanden sein. ### GET products Mit diesem Endpunkt können Sie eine Liste aller Produkte im System abrufen. Optional kann die Ergebnismenge mithilfe von Filterparametern eingeschränkt werden, beispielsweise auf Produkte, die einer bestimmten Kategorie zugeordnet sind (`inCategory`) oder aus einer bestimmten Kategorie ausgeschlossen werden sollen (`notInCategory`). Beide Parameter dürfen nicht gleichzeitig verwendet werden. Damit der Endpunkt verwendet werden kann, müssen die entsprechenden Berechtigungen zum Lesen von Produkten vorhanden sein. #### Reihenfolge bei `inCategory` Wird `inCategory` verwendet und **kein eigener `sort`-Parameter** angegeben, liefert der Endpunkt die Produkte genau in der **im Shop gepflegten Kategoriereihenfolge**. `GET products?inCategory={categoryId}` und [`GET categories/{categoryId}/products`](/schnittstellen/admin-interface-api/api-referenz-kategorien#get-categoriescategoryidproducts) sind dabei gleichwertig: Der Kategorie-Endpunkt setzt intern nichts anderes als `inCategory` und wertet denselben Code aus. Es gibt also keinen Grund, für die Kategoriereihenfolge auf den anderen Endpunkt zu wechseln. Sobald Sie selbst einen `sort`-Parameter setzen, gilt die Kategoriereihenfolge für **keinen der beiden Endpunkte** mehr — Ihre Sortierung ersetzt sie vollständig. Wenn Sie die gepflegte Reihenfolge benötigen, lassen Sie `sort` einfach weg. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products?subshopId=deutsch ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": false, "items": [ { "active": "always", "custom": { ... }, "descr": "Lässiges Barbour-Shirt aus Baumwoll-Piqué mit Langarm. Gearbeitet in gerader, normaler Passform (Regular Fit) mit Kontrastbesatz im 'Barbour-Tartan' an der Knopfleiste und im Kragen. Mit klassischem Polokragen, Ärmelbündchen und gesticktem Barbour-Logo. Ein Mode-Klassiker für die Freizeit, in dem sich jeder Mann wohlfühlt. Länge ca. 75 cm.Farbe: Navy. Original Barbour. Größen: M (48), L (50), XL (52/54), XXL (56/58), XXXL (58/60) Reine Baumwolle.", "hasVariants": false, "id": "11-1701", "itemNumber": "11-1701", "name": "Tartan-Langarm-Polo in Navy", "price": { "price": "89.900000", "scheduledPrices": [] }, "taxRateId": "1", "timestampCreatedAt": "2024-11-14T10:41:25.000Z", "timestampUpdatedAt": "2025-01-24T09:28:06.000Z" } ], "nextPageToken": "WzAuMCwiMTEtMjgxNV9kZXV0c2NoXzMiXQ", "totalCount": 1296 } ``` #### Filterfelder Alle Produktdatenfelder — benutzerdefinierte Felder mit dem Präfix `custom.` (z. B. `filter_eq[custom.brand]=Barbour`). Filterbar heißt nicht „mit jeder Operation kombinierbar": **Welche Filteroperationen erlaubt sind, hängt am Datentyp des Feldes.** Auf einem Enum-Feld wie `active` sind z. B. nur `eq` und `neq` zulässig, `contains` führt zu `400 Bad Request` mit dem Typ `illegalOperation`. Die vollständige Matrix steht in den [API Basics – Erlaubte Operationen je Feldtyp](/schnittstellen/admin-interface-api/api-basics#erlaubte-operationen-je-feldtyp). Zusätzlich zu den Produktdatenfeldern stehen folgende Filter als **einfache Query-Parameter** zur Verfügung (ohne `filter_`-Präfix und ohne Klammern): | **Parameter** | **Beschreibung** | | ----------------------------- | --------------------------------------------------------------- | | `inCategory={categoryId}` | Nur Produkte, die dieser Kategorie zugewiesen sind. | | `notInCategory={categoryId}` | Nur Produkte, die dieser Kategorie *nicht* zugewiesen sind. | | `notInAnyCategory=true` | Nur Produkte, die keiner Kategorie zugewiesen sind. | | `inSetProduct={productId}` | Nur Produkte, die Bestandteil dieses Set-Produkts sind. | | `notInSetProduct={productId}` | Nur Produkte, die *nicht* Bestandteil dieses Set-Produkts sind. | `inCategory` und `notInCategory` bzw. `inSetProduct` und `notInSetProduct` dürfen nicht gleichzeitig gesetzt werden (Fehler `invalidCombination`). #### Sortierfelder Alle Produktdatenfelder außer Feldern vom Typ `Liste`, `Map`, `Bild` und `Video` — diese führen zu `400 Bad Request` mit dem Typ `invalidValue`. Syntax: `sort=:asc` bzw. `sort=:desc`. Der Feldname ist **Pflicht**; eine Kurzform wie `sort=asc` ist ein Syntaxfehler. Mehrere Sortierkriterien werden über mehrere `sort`-Parameter übergeben — siehe [API Basics – Sortierung](/schnittstellen/admin-interface-api/api-basics#sortierung). #### Sonstige Parameter `from` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Produkten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | "stage" ist ungültig
    `size` ∉ \[1;300]
    `pageToken` ist keine Zahl oder kleiner als 0.
    `from` ist größer als 9999.
    Es wird versucht, Produkte nach einem Feld vom Typ `Liste`, `Map`, `Bild` oder `Video` zu sortieren. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "illegalOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "invalidCharacters" | Ein Filterwert ist ungültig.
    `size` ist keine Ganzzahl. | | 400 Bad Request | "invalidCombination" | Die Filter `inCategory` und `notInCategory` oder `inSetProduct` und `notInSetProduct` sind gleichzeitig gesetzt. | | 503 Service Unavailable | "serviceUnavailable" | Das Lesen von Daten ist fehlgeschlagen. | ### GET products/ Mit diesem Endpunkt können Sie die vollständigen Daten eines einzelnen Produkts abrufen. Geben Sie dazu die Produkt-ID als Pfadparameter an. Neben den Basisdaten werden auch benutzerdefinierte Felder zurückgegeben. Damit der Endpunkt verwendet werden kann, müssen die entsprechenden Berechtigungen zum Lesen von Produkten vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/11-1701?subshopId=deutsch ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": "always", "custom": { "liste": [ "123", "234", "456" ], "map": { "a": "b", "c": "d", "e": "f" }, "robotsNoFollow": false, "robotsNoIndex": false, "weight": 0.33 }, "descr": "Lässiges Barbour-Shirt aus Baumwoll-Piqué mit Langarm. Gearbeitet in gerader, normaler Passform (Regular Fit) mit Kontrastbesatz im 'Barbour-Tartan' an der Knopfleiste und im Kragen. Mit klassischem Polokragen, Ärmelbündchen und gesticktem Barbour-Logo. Ein Mode-Klassiker für die Freizeit, in dem sich jeder Mann wohlfühlt. Länge ca. 75 cm.Farbe: Navy. Original Barbour. Größen: M (48), L (50), XL (52/54), XXL (56/58), XXXL (58/60) Reine Baumwolle.", "hasVariants": false, "id": "11-1701", "itemNumber": "11-1701", "name": "Tartan-Langarm-Polo in Navy", "price": { "price": "89.900000", "scheduledPrices": [ { "price": "79.900000", "startDate": "2026-08-01T00:00:00.000Z", "endDate": "2026-08-31T23:59:59.000Z", "promotionInfo": "Sommeraktion", "validForDiscount": true } ] }, "ratingApprovalConfig": { "maximumRating": 5.0, "minimumRating": 1.0 }, "statistics": { "averageRating": 4.5, "ratingCount": 12 }, "statisticsPerPoint": { "1": 0, "2": 1, "3": 2, "4": 3, "5": 6 }, "taxRateId": "1", "timestampCreatedAt": "2024-11-14T10:41:25.000Z", "timestampUpdatedAt": "2025-01-24T09:28:06.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | -------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Produkten. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben. | | 404 Not Found | | Produkt mit `id`=`{id}` wurde nicht gefunden. | ### GET products//url Mit diesem Endpunkt können Sie die vollständige URL eines Produkts abrufen. Für die Nutzung dieses Endpunkts sind Leseberechtigungen für Produkt-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/143-68071/url?subshopId=deutsch ``` #### Antwort ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/SEOURL/ ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | -------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Produkten. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben. | ### GET products/testRule Mit diesem Endpunkt können Sie gezielt Produkte abrufen, die einer oder mehreren angegebenen Regeln entsprechen. Die Regeln werden als JSON-formatiertes Array in der Query-URL übergeben und ermöglichen eine flexible Filterung nach Produktfeldern wie beispielsweise Aktivitätsstatus, Artikelnummern oder Preisangaben. Die Regeln dürfen nur gültige Felder und zulässige Operatoren enthalten. Damit dieser Endpunkt verwendet werden kann, müssen die entsprechenden Berechtigungen zum Lesen von Produktdaten vorhanden sein. #### Beispiel Die Regeln werden in der URL als JSON-Array kodiert und über den Parameter `rules` übergeben. Um korrekt interpretiert zu werden, muss dieser Parameter URL-dekodiert werden. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/testRule?size=100&rules=%5B%7B%22field%22%3A%22&active%22%2C%22mode%22%3A%22eq%22%2C%22value%22%3A%22always%22%7D%2C%7B%22field%22%3A%22itemNumber%22%2C%22mode%22%3A%22contains%22%2C%22value%22%3A%225%22%7D%5D&& ``` Die URL ruft Produkte ab, die zwei Bedingungen erfüllen: 1. Das Feld `active`muss den Wert`always`haben.
    Es werden nur Produkte berücksichtigt, die dauerhaft aktiv sind. 2. Die Artikelnummer (`itemNumber`) muss die Ziffer „5“ enthalten.
    Es werden nur Produkte ausgewählt, deren Artikelnummer irgendwo die „5“ enthält (beispielsweise `11-2518`). Filter und Sortierungen auf Preisfeldern greifen auf den Standardpreis zu. Geplante Aktionspreise werden dabei nicht berücksichtigt. #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "active": "always", "custom": { "brand": "", "commission": 0, "commissionTaxRate": "", "crossSelling": [], "customNumber": "", "ean": "", "filterField": "", "image": [], "isbn": "", "mainCategory": "", "metaDescription": "", "metaDescriptionSetManually": false, "metaTitle": "", "metaTitleSetManually": false, "multiProducts": "", "oneTimeFee": 0, "oneTimeFeeTaxRate": "", "productDiscount": 0, "productDiscountAbsolute": false, "productType": "", "robotsNoFollow": false, "robotsNoIndex": false, "validForDiscount": false, "video": "", "voucherProductActive": false, "voucherProductHtmlTemplate": "", "voucherProductPrice": false, "voucherProductTemplate": "", "weight": 0 }, "descr": "Dieses weiße Poloshirt ist alles andere als gewöhnlich, sondern ...", "hasVariants": true, "id": "11-2451", "itemNumber": "11-2451", "name": "Samtweiches Polo aus Luxusjersey", "price": { "price": "89.900000", "scheduledPrices": [] }, "taxRateId": "1", "timestampCreatedAt": "2025-02-14T10:50:38.000Z", "timestampUpdatedAt": "2025-04-28T10:24:24.000Z" }, { "active": "always", "custom": { "brand": "", "commission": 0, "commissionTaxRate": "", "crossSelling": [], "customNumber": "", "ean": "", "filterField": "", "image": [], "isbn": "", "mainCategory": "", "metaDescription": "", "metaDescriptionSetManually": false, "metaTitle": "", "metaTitleSetManually": false, "multiProducts": "", "oneTimeFee": 0, "oneTimeFeeTaxRate": "", "productDiscount": 0, "productDiscountAbsolute": false, "productType": "", "robotsNoFollow": false, "robotsNoIndex": false, "validForDiscount": false, "video": "", "voucherProductActive": false, "voucherProductHtmlTemplate": "", "voucherProductPrice": false, "voucherProductTemplate": "", "weight": 0 }, "descr": "Einmal angezogen, wollen Sie aus diesem kuschelig weichen Flane...", "hasVariants": true, "id": "11-2518", "itemNumber": "11-2518", "name": "Lieblingshemd aus Fischgrat-Gewebe", "price": { "price": "79.900000", "scheduledPrices": [] }, "taxRateId": "1", "timestampCreatedAt": "2025-02-14T10:50:45.000Z", "timestampUpdatedAt": "2025-04-28T10:24:24.000Z" }, ... ], "nextPageToken": "WzAuMCwiMTQzLTY4MDcxX2RldXRzY2hfMyJd", "totalCount": 64, "warnings": { "invalidValue": [], "unknownFilters": [], "wrongOperators": [] } } ``` #### Mögliche Werte für `mode` `gt` (größer), `gte` (größer oder gleich), `lt` (kleiner), `lte` (kleiner oder gleich), `eq` (gleich), `neq` (ungleich), `contains` (enthält), `notcontains` (nicht enthält) #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Produkt-Daten. | | 400 Bad Request | | Regeln konnten nicht geparst werden. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | | 400 Bad Request | "unknownDataField" | Ein Sortierfeld ist ungültig. | | 400 Bad Request | "invalidValue" | | ### POST products Mit dem Endpunkt `/products` können neue Produkte im Shop-System angelegt werden. Alle für die Erstellung erforderlichen Produktinformationen müssen im Request Body übergeben werden. Die Antwort enthält die vollständigen Produktdaten des neu erstellten Produkts im JSON-Format. Zum Erstellen eines Produkts sind entsprechende Berechtigungen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "custom": { "liste": [], "map": {} }, "active": "always", "descr": "This is a new Produkt", "itemNumber": "new", "name": "NewProdukt", "price": "1", "taxRateId": "19" } ``` Der Preis darf wie im Beispiel als String übergeben werden. Sollen zugleich Aktionspreise gepflegt werden, ist die Objektform zu verwenden, die der Abschnitt [Preisfelder in Requests](#preisfelder-in-requests) beschreibt. #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": "always", "custom": { "brand": "", "commission": { "source": "0.0", "parsedValue": 0 }, "commissionTaxRate": "", "crossSelling": [], "customNumber": "", "ean": "", "filterField": "", "image": [], "isbn": "", "liste": [], "map": {}, ... "weight": { "source": "0.0", "parsedValue": 0 } }, "descr": "This is a new Produkt", "hasVariants": false, "id": "144-46864", "itemNumber": "new", "name": "NewProdukt", "price": { "price": "1.000000", "scheduledPrices": [] }, "taxRateId": "19", "timestampCreatedAt": "2025-05-09T14:57:36.000Z", "timestampUpdatedAt": "2025-05-09T14:57:36.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Produkten. | | 400 Bad Request | | Der Request-Body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage oder ein ungültiger Subshop angegeben.
    Ein Feld enthält den Wert `null`.
    Ein Wert hat den Typ, der mit dem Typ aus der Konfiguration nicht übereinstimmt.
    Ein Preis-Wert kann nicht geparst werden.
    Ein Feld vom Typ `Map` hat einen Schlüssel, der kein String ist.
    Ein Feld vom Typ `List` ist kein Array von Strings.
    Ein Zeitwert ist nicht in ISO 8601 Format.
    Bild-Daten von einem Bild sind kein Array von Objekten.
    `id` des Formats oder `path` sind keine Strings. | | 400 Bad Request | "invalidFormat" | `custom` ist kein Objekt. | | 400 Bad Request | "unknownDataField" | Ein nicht existierendes Produktdatenfeld wurde im Request-Body angegeben. | | 400 Bad Request | "notManualEditable" | Ein nicht bearbeitbares Produktdatenfeld wurde im Request-Body angegeben. | Fehler in geplanten Aktionspreisen werden je Eintrag gemeldet. Die Schlüssel beschreibt der Abschnitt [Validierung und Fehlerschlüssel](#validierung-und-fehlerschlüssel). ### PUT products/ Mit dem Endpunkt `products/{productId}` können Produktdaten aktualisiert werden. Wird ein Produkt mit der angegebenen ID nicht gefunden, kann bei gesetztem Parameter `createMissing=yes` automatisch ein neues Produkt angelegt werden. Die vollständigen Produktdaten müssen im Request-Body übergeben werden. Das optionale Feld `set` kann benutzt werden, um andere Produkte zusammen mit dem Aktuellen einem Set zuzuweisen. Alternativ können [die Endpunkte für Set-Produkte](#methoden-für-set-produkte) genutzt werden. Zum Bearbeiten oder Anlegen eines Produkts sind entsprechende Berechtigungen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/11-1966 ``` #### Request-Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "custom": { "brand": "", "commission": 0, "commissionTaxRate": "", "crossSelling": [], "customNumber": "", "ean": "", "filterField": "", "image": [], "isbn": "", "mainCategory": "", "metaDescription": "", "metaDescriptionSetManually": false, "metaTitle": "", "metaTitleSetManually": false, "multiProducts": "", "oneTimeFee": 0, "oneTimeFeeTaxRate": "", "productDiscount": 0, "productDiscountAbsolute": false, "productType": "", "robotsNoFollow": false, "robotsNoIndex": false, "validForDiscount": false, "video": "", "voucherProductActive": false, "voucherProductHtmlTemplate": "", "voucherProductPrice": false, "voucherProductTemplate": "", "weight": 0 }, "active": "always", "descr": "Jedes Stück, das von dem Strickunternehmen Kero Design kommt, ist ein echtes Unikat! Genau wie dieser Cardigan: Hier mischen sich zarte und kräftige Blautöne und ergeben ein effektvolles Strickkunstwerk. Diese handgestrickte Optik mit ihren schönen Farbverläufen erhält der Cardigan vor allem durch seine aufwendig von Hand gefärbten Garne. Reine Baumwolle macht die Strickjacke schön leicht und weich. Ein echter Blickfang und sehr besonders! Mit langen Ärmeln, Rundhals und Perlmutt-Knöpfen.
    Gerade Form (Regular Fit). Länge ca. 60 cm.Farbe: Multicolor Blue. Original Kero Design. 65 % Baumwolle (Bio-Baumwolle), 35 % Baumwolle.", "itemNumber": "12-2144", "name": "Cardigan 'Amelia'", "price": { "price": "139.00", "scheduledPrices": [ { "price": "119.00", "startDate": "2026-08-01T00:00:00.000Z", "endDate": "2026-08-31T23:59:59.000Z", "promotionInfo": "Sommeraktion", "validForDiscount": true } ] }, "taxRateId": "1", "set": [ { "id": "11-2497", "quantityFactor": 1, "usePrice": true, "fixQuantity": false, "hidden": false }, { "id": "11-2492", "quantityFactor": 1, "usePrice": true, "fixQuantity": false, "hidden": false } ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": "always", "custom": { "brand": "", "commission": 0, "commissionTaxRate": "", "crossSelling": [], "customNumber": "", "ean": "", "filterField": "", "image": [], "isbn": "", "mainCategory": "", "metaDescription": "", "metaDescriptionSetManually": false, "metaTitle": "", "metaTitleSetManually": false, "multiProducts": "", "oneTimeFee": 0, "oneTimeFeeTaxRate": "", "productDiscount": 0, "productDiscountAbsolute": false, "productType": "", "robotsNoFollow": false, "robotsNoIndex": false, "validForDiscount": false, "video": "", "voucherProductActive": false, "voucherProductHtmlTemplate": "", "voucherProductPrice": false, "voucherProductTemplate": "", "weight": 0 }, "descr": "Jedes Stück, das von dem Strickunternehmen Kero Design kommt, ist ein echtes Unikat! Genau wie dieser Cardigan: Hier mischen sich zarte und kräftige Blautöne und ergeben ein effektvolles Strickkunstwerk. Diese handgestrickte Optik mit ihren schönen Farbverläufen erhält der Cardigan vor allem durch seine aufwendig von Hand gefärbten Garne. Reine Baumwolle macht die Strickjacke schön leicht und weich. Ein echter Blickfang und sehr besonders! Mit langen Ärmeln, Rundhals und Perlmutt-Knöpfen.
    Gerade Form (Regular Fit). Länge ca. 60 cm.Farbe: Multicolor Blue. Original Kero Design. 65 % Baumwolle (Bio-Baumwolle), 35 % Baumwolle.", "hasVariants": true, "id": "12-2144", "itemNumber": "12-2144", "name": "Cardigan 'Amelia'", "price": { "price": "139.000000", "scheduledPrices": [ { "price": "119.000000", "startDate": "2026-08-01T00:00:00.000Z", "endDate": "2026-08-31T23:59:59.000Z", "promotionInfo": "Sommeraktion", "validForDiscount": true } ] }, "taxRateId": "1", "timestampCreatedAt": "2025-02-14T10:54:45.000Z", "timestampUpdatedAt": "2025-05-10T16:19:36.000Z" } ``` Die Antwort enthält keinen Set-Preis. Er wird nicht gespeichert, sondern bei Bedarf berechnet. Wie Sie ihn abrufen, beschreibt der Abschnitt [POST products/setproducts/preview](#post-productssetproductspreview). #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Produkten. | | 400 Bad Request | | Der Request-Body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | Die `productId` im Pfad ist ungültig.
    Es wurde eine ungültige Stage oder ein ungültiger Subshop angegeben.
    Ein Feld enthält den Wert `null`.
    Ein Wert hat den Typ, der mit dem Typ aus der Konfiguration nicht übereinstimmt.
    Ein Preis-Wert kann nicht geparst werden.
    Ein Feld vom Typ `Map` hat einen Schlüssel, der kein String ist.
    Ein Feld vom Typ `List` ist kein Array von Strings.
    Ein Zeitwert ist nicht in ISO 8601 Format.
    Bild-Daten von einem Bild sind kein Array von Objekten.
    `id` des Formats oder `path` sind keine Strings. | | 400 Bad Request | "invalidFormat" | `custom` ist kein Objekt. | | 400 Bad Request | "unknownDataField" | Ein nicht existierendes Produktdatenfeld wurde im Request-Body angegeben. | | 400 Bad Request | "notManualEditable" | Ein nicht bearbeitbares Produktdatenfeld wurde im Request-Body angegeben. | | 400 Bad Request | "protectedFieldWriteError" | Ein geschütztes Produktdatenfeld wurde im Request-Body angegeben und der Benutzer hat keine Berechtigung, dieses Feld zu ändern. | | 503 Service Unavailable | "internalError" | Das Produkt konnte nach mehreren Versuchen aufgrund von Versionskonflikten nicht gespeichert werden. | | 404 Not Found | | Das Produkt mit `id={id}` wurde nicht gefunden und der Parameter `createMissing` ist nicht auf `yes` gesetzt. | ### DELETE products/ Mit dem Endpunkt `products/{productId}` kann ein Produkt mit der angegebenen ID dauerhaft gelöscht werden. Dieser Vorgang entfernt das Produkt vollständig aus dem System. Zum Löschen eines Produkts sind entsprechende Berechtigungen erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/123456 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Produkten. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben. | | 404 Not Found | | Das Produkt mit `id={id}` existiert nicht. | ## Bulk-Methoden für Produkte In diesem Abschnitt werden die Bulk-Endpunkte beschrieben, mit denen mehrere Datensätze in einem einzigen Request abgefragt oder verarbeitet werden können. ### POST bulk/products Ermöglicht das massenhafte Erstellen und Aktualisieren von Produktdaten in einem einzigen Request. Der Request-Body ist ein JSON-Array, in dem jedes Element ein Produkt mit ID beschreibt. Erstell- und Schreibrechte für Produkte sind erforderlich. Standardmäßig werden nur Produkte aktualisiert. Wird der Parameter createMissing=yes gesetzt, dann werden Produkte in der Anfrage die noch nicht existieren automatisch neues angelegt. In einem Request können maximal 1000 Einträge verarbeitet werden. Dieses Limit gilt gemeinsam für alle Bulk-Endpunkte der API - siehe [API Basics – Bulk-Endpunkte](/schnittstellen/admin-interface-api/api-basics#bulk-endpunkte). #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/bulk/products ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "custom": { "liste": [], "map": {} }, "id": "144-46864", "active": "always", "descr": "This is a new Produkt", "itemNumber": "new", "name": "NewProdukt", "price": "1", "taxRateId": "19" }, { "custom": { "liste": [], "map": {} }, "id": "145-26318", "active": "always", "descr": "This is an existing Produkt", "itemNumber": "existing", "name": "existingProduct", "price": "1", "taxRateId": "19" } ] ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": ["145-26318"], "skippedLines": [{ "lineNumber": 0, "productId": "144-46864", "errorType": "notFound", "fieldErrors": {} }] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen oder aktualisieren von Produkten. | | 400 Bad Request | | Der Request-Body konnte nicht geladen werden.
    Es wurden mehr als 1000 Einträge angegeben. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage oder ein ungültiger Subshop angegeben.
    Ein Feld enthält den Wert `null`.
    Ein Wert hat den Typ, der mit dem Typ aus der Konfiguration nicht übereinstimmt.
    Ein Preis-Wert kann nicht geparst werden.
    Ein Feld vom Typ `Map` hat einen Schlüssel, der kein String ist.
    Ein Feld vom Typ `List` ist kein Array von Strings.
    Ein Zeitwert ist nicht in ISO 8601 Format.
    Bild-Daten von einem Bild sind kein Array von Objekten.
    `id` des Formats oder `path` sind keine Strings. | | 400 Bad Request | "invalidFormat" | `custom` ist kein Objekt. | | 400 Bad Request | "unknownDataField" | Ein nicht existierendes Produktdatenfeld wurde im Request-Body angegeben. | | 400 Bad Request | "notManualEditable" | Ein nicht bearbeitbares Produktdatenfeld wurde im Request-Body angegeben. | ## Methoden für Variantenattribute Mit den Endpunkten im Bereich `products/variants/` lassen sich die Variantenattribute und zugehörige Optionen verwalten, die zur Bildung von Produktvarianten im Shop verwendet werden. Sie können neue Attribut-Optionen hinzufügen, bestehende anpassen oder Attribute löschen. Ebenso können Sie die Anzeige-Reihenfolge von Optionen ändern oder gezielt einzelne Optionen abfragen. Für alle hier dokumentierten Endpunkte ist eine gültige Authentifizierung erforderlich. Zusätzlich benötigen Sie die Berechtigungen zum Lesen, Erstellen oder Bearbeiten von Produktdaten. ### GET products/variants Mit diesem Endpunkt kann eine Liste aller im Shop-System definierten Varianten-Attribute und deren verfügbaren Optionen abgerufen werden. Die Antwort gibt Aufschluss darüber, welche Attributnamen (beispielsweise „Größe“, „Farbe“) verwendet werden und welche Ausprägungen pro Attribut zur Verfügung stehen. Dies ist besonders hilfreich für das Anlegen oder Bearbeiten von Produktvarianten. Für diesen Endpunkt ist eine gültige Authentifizierung erforderlich. Sie müssen über die Berechtigung zum Lesen von Produkten verfügen. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/variants ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "name": "Größe", "options": [ { "id": 1, "option": "L" }, { "id": 2, "option": "XL" } ] }, { "name": "Farbe", "options": [ { "id": 4, "option": "Rot" }, { "id": 3, "option": "Grün" } ] } ] ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | --------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Produktvarianten. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben. | ### GET products/variants/ Mit diesem Endpunkt kann entweder ein Varianten-Attribut mit seinen zugehörigen Optionen oder eine einzelne Variante-Option abgerufen werden. Wird in der URL ein Attributname (beispielsweise „Farbe“) übergeben, liefert die Antwort alle Optionen zu diesem Attribut. Wird hingegen eine Options-ID übergeben, muss zusätzlich der Parameter `singleOption=yes` gesetzt werden, um die Daten zu einer konkreten Variante-Option abzurufen. Die Suche nach dem Attributnamen erfolgt unabhängig von der Groß-/Kleinschreibung. Für die Nutzung dieses Endpunkts ist eine gültige Authentifizierung notwendig. Sie benötigen die Berechtigung zum Lesen von Produkten. #### Beispiel (Attribut) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/variants/Farbe ``` #### Antwort (Attribut) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "Farbe", "options": [ { "id": 4, "option": "Rot" }, { "id": 3, "option": "Grün" } ] } ``` #### Beispiel (Option) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/variants/4?singleOption=yes ``` #### Antwort (Option) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": 4, "attribute": "Farbe", "option": "Rot" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Produktvarianten. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben.
    Die übergebene `id` ist keine positive Ganzzahl (bei `singleOption=yes`). | | 404 Not Found | | Die Option oder das Attribute wurde nicht gefunden. | ### POST products/variants Mit diesem Endpunkt wird ein neues Varianten-Attribut mit beliebigen Optionswerten erstellt. Sollte das Attribut bereits existieren (Groß-/Kleinschreibung wird nicht berücksichtigt), wird es um die neuen, bislang nicht vorhandenen Optionen ergänzt. Ist eine der angegebenen Optionen für das Attribut bereits vorhanden, wird der Vorgang mit einem Konfliktfehler (409) abgebrochen. Für die Nutzung dieses Endpunkts ist eine gültige Authentifizierung erforderlich. Sie benötigen die Berechtigung zum Erstellen von Produkten. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/variants ``` #### Request-Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "attribute": "color", "options": [ "red", "blue", "white" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "attribute": "color", "options": [ { "id": 23, "option": "red" }, { "id": 24, "option": "blue" }, { "id": 25, "option": "white" } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Produktvarianten. | | 400 Bad Request | | Der Request-Body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben.
    `attribute` oder `options` sind leer.
    Die Länge von `attribute` oder von einzelnen Optionen ist gleich 0 oder größer als 128 Zeichen. | | 400 Bad Request | "missing" | Parameter `attribute` oder `options` fehlen. | | 400 Bad Request | "invalidFormat" | `attribute` ist kein String.
    `options` ist kein Array. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request-Body angegeben. | | 409 Conflict | "variantAlreadyExists" | Ein Attribut mit der angegebenen Option existiert bereits. | ### PUT products/variants/ Mit diesem Endpunkt wird ein bestehendes Varianten-Attribut aktualisiert. Die Suche nach dem Attributnamen erfolgt unabhängig von der Groß-/Kleinschreibung. Es können neue Optionen hinzugefügt, bestehende bearbeitet und die Reihenfolge der Optionen geändert werden. Das Umbenennen des Attributs ist über den optionalen Parameter `newAttributeName` möglich. Bereits existierende Optionen, die im Request-Body nicht enthalten sind, bleiben unverändert bestehen. Für die Nutzung dieses Endpunkts ist eine gültige Authentifizierung erforderlich. Sie benötigen die Berechtigung zum Schreiben von Produkten. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/variants/color ``` #### Request-Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "options": [ { "option": "blueUpd", "id": 24 }, { "id": 23, "option": "red" }, { "id": 25, "option": "white" }, { "option": "newColor" } ], "newAttributeName": "colorUpd" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "attribute": "colorUpd" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ------------------ | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Bearbeiten von Produktvarianten. | | 400 Bad Request | | Der Request-Body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben.
    `options` ist kein Array.
    Die Länge von `newAttributeName` oder von einzelnen Optionen ist gleich 0 oder größer als 128 Zeichen. | | 400 Bad Request | "missing" | `attributeId` fehlt. | | 404 Not Found | | Das Attribut wurde nicht gefunden. | | 503 Internal Error | "internalError" | Das Aktualisieren ist fehlgeschlagen. | ### DELETE products/variants/ Mit diesem Endpunkt können Sie entweder ein Varianten-Attribut samt aller zugehörigen Optionen oder eine einzelne Option löschen. Wird das Attribut derzeit noch von einem Produkt verwendet, wird der Vorgang mit einem Konfliktfehler abgebrochen. Für die Nutzung dieses Endpunkts ist eine gültige Authentifizierung erforderlich. Sie benötigen die Berechtigung zum Löschen von Produktdaten. Wird in der URL ein Attributname übergeben, werden das Attribut und alle zugehörigen Optionen gelöscht. Die Suche nach dem Attributnamen erfolgt unabhängig von der Groß-/Kleinschreibung. Wird hingegen eine Options-ID übergeben, muss zusätzlich der Parameter `singleOption=yes` gesetzt werden, um nur diese einzelne Option zu löschen. #### Beispiel (Attribut) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/variants/color ``` #### Antwort (Attribut) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Beispiel (Option) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/variants/4?singleOption=yes ``` #### Antwort (Option) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": 4, "attribute": "Farbe", "option": "Rot" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Produktvarianten. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben.
    Die übergebene `id` ist keine positive Ganzzahl (bei `singleOption=yes`). | | 404 Not Found | | Die Option oder das Attribut wurden nicht gefunden. | | 409 Conflict | "variantInUse" | Dieses Varianten-Attribut wird von einer Produktvariante verwendet. | ## Methoden für Produktvarianten Die folgenden Endpunkte ermöglichen das Verwalten von Produktvarianten innerhalb eines bestehenden Produkts. Varianten stellen spezifische Ausprägungen eines Produkts dar (beispielsweise Größen oder Farben) und basieren auf den zuvor definierten Variantenattributen. Die API erlaubt es, Varianten einzeln abzurufen, zu erstellen, zu aktualisieren oder zu löschen sowie komplette Variantenkombinationen automatisch zu erzeugen. Für alle Endpunkte in diesem Abschnitt ist sicherzustellen, dass die entsprechenden Lese-, Schreib- oder Löschberechtigungen für Produktvarianten vorliegen. Auch Varianten tragen ihren Preis als Objekt. Setzt eine Variante ein eigenes Preisfeld, ersetzt dieses den Standardpreis und den Zeitplan des Basisprodukts gemeinsam. Eine Variante mit eigenem Preis und ohne Aktionspreise erbt die Aktion des Basisprodukts also nicht. Setzt eine Variante kein eigenes Preisfeld, liefert die Antwort für dieses Feld `null` und nicht den Wert des Basisprodukts. Anbindungen müssen diesen Fall abfangen, der Typ ist `object | null`. ### GET products//variants Mit diesem Endpunkt kann eine Liste aller Varianten für das angegebene Produkt geladen werden. Varianten sind Produktversionen, die sich durch unterschiedliche Attributkombinationen (beispielsweise Größe oder Farbe) vom Hauptprodukt unterscheiden. Die Antwort enthält grundlegende Produktdaten sowie die zugehörigen Attributwerte unter `selection`. Um diesen Endpunkt nutzen zu können, sind entsprechende Berechtigungen zum Lesen von Produktvarianten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/11-1701/variants ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "active": "always", "custom": { "weight": 0.33 }, "descr": null, "id": "8310", "itemNumber": "11-1701-M", "name": null, "price": { "price": "89.900000", "scheduledPrices": [] }, "selection": { "Größe": "M" }, "taxRateId": null }, ... ], "nextPageToken": "MTAw", "totalCount": 6 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | --------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Produktvarianten. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben. | | 404 Not Found | | Das Produkt mit `id={productId}` wurde nicht gefunden. | ### GET products//variants/ Mit diesem Endpunkt kann eine bestimmte Produktvariante anhand ihrer ID innerhalb eines Produkts geladen werden. Die Produkt-ID wird als Teil der URL übergeben, ebenso die Varianten-ID. Die Antwort enthält die zugehörigen Variantendaten inklusive Preis, Artikelnummer, Auswahlattribute (`selection`) und weiterer Detailinformationen. Für die Nutzung dieses Endpunkts sind entsprechende Berechtigungen zum Lesen von Produktvarianten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/11-1701/variants/8310 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": "always", "custom": { "weight": 0.33 }, "descr": null, "id": "8310", "itemNumber": "11-1701-M", "name": null, "price": { "price": "89.900000", "scheduledPrices": [] }, "selection": { "Größe": "M" }, "taxRateId": null } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | --------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Produktvarianten. | | 400 Bad Request | "invalidValue" | `id` ist ungültig. Es wurde eine ungültige Stage angegeben. | | 404 Not Found | | Produkt mit `id`=`{productId}` wurde nicht gefunden. Produktvariante mit `id={variantId}` wurde nicht gefunden. | ### PUT products//variants/ Mit diesem Endpunkt können die Daten einer bestimmten Produktvariante anhand ihrer Produkt-ID und Varianten-ID aktualisiert werden. Die Variante wird anhand der angegebenen ID identifiziert und mit den im Request-Body übermittelten Werten überschrieben. Für die Nutzung dieses Endpunkts sind Schreibrechte für Produktvarianten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/11-1701/variants/8310 ``` #### Request-Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": "always", "custom": { "weight": 0.33 }, "descr": null, "id": "8310", "itemNumber": "11-1701-M", "name": null, "price": "89.900000", "selection": { "Größe": "M" }, "set": [], "taxRateId": null } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": "always", "custom": { "weight": 0.33 }, "descr": null, "id": "8310", "itemNumber": "11-1701-M", "name": null, "price": { "price": "89.900000", "scheduledPrices": [] }, "selection": { "Größe": "M" }, "taxRateId": null } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Produktvarianten. | | 400 Bad Request | | Der Request-Body konnte nicht geladen werden | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben oder ein ungültiger Subshop angegeben.
    `custom` ist kein Objekt.
    Ein Feld enthält den Wert `null`.
    Ein Wert hat den Typ, der mit dem Typ aus der Konfiguration nicht übereinstimmt.
    Ein Preis-Wert kann nicht geparst werden.
    Ein Feld vom Typ `Map` hat einen Schlüssel, der kein String ist.
    Ein Feld vom Typ `List` ist kein Array von Strings.
    Ein Zeitwert ist nicht in ISO 8601 Format.
    Bild-Daten von einem Bild sind kein Array von Objekten.
    `id` des Formats oder `path` sind keine Strings. | | 400 Bad Request | "unknownDataField" | Ein nicht existierendes Produktdatenfeld wurde im Request-Body angegeben. | | 404 Not Found | | Produkt mit `id`=`{productId}` wurde nicht gefunden
    Produktvariante mit `id={variantId}` wurde nicht gefunden. | | 400 Bad Request | "invalidFormat" | `custom` ist kein Objekt. | | 503 Service Unavailable | "internalError" | Das Produkt konnte nach mehreren Versuchen aufgrund von Versionskonflikten nicht gespeichert werden. | ### POST products//variantAttributes Mit diesem Endpunkt können für ein bestimmtes Produkt Varianten automatisch aus den übergebenen Attributen erzeugt werden. Dabei wird jede mögliche Kombination der Attribut-Optionen als eigene Produktvariante angelegt. Wenn dem Produkt bisher nicht zugewiesene Attribute ergänzt oder vorhandene Attribute entfernt werden, wird der Vorgang standardmäßig abgebrochen und es wird ein 400-Fehler mit dem Fehlertyp `conflict` zurückgegeben. Um diesen Abbruch zu umgehen, kann der optionale Parameter `force=yes` verwendet werden. In diesem Fall werden alle bisherigen Kombinationen gelöscht und durch die neuen ersetzt. Für die Nutzung dieses Endpunkts sind Schreibrechte für Produktvarianten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/11-1701/variantAttributes ``` #### Request-Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "attributes": [ "größe", "farbe" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Produktvarianten. | | 400 Bad Request | | Der Request-Body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben.
    Ein angegebenes Attribut existiert nicht. | | 400 Bad Request | "missing" | `attributes` fehlt im Request-Body. | | 400 Bad Request | "invalidFormat" | `attributes` ist kein Array.
    Ein Element in `attributes` ist kein String. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request-Body angegeben. | | 400 Bad Request | "conflict" | Die Variantenattribute des Produkts haben sich geändert. Bestehende Varianten würden gelöscht. Verwenden Sie `force=yes`, um den Vorgang trotzdem durchzuführen. | | 404 Not Found | | Das Produkt mit `id`=`{productId}` wurde nicht gefunden. | | 503 Service Unavailable | "internalError" | Das Produkt konnte nicht aktualisiert werden. | ### POST products//variants/manage Dieser Endpunkt ermöglicht es, gezielt bestimmte Varianten-Kombinationen für ein bestehendes Produkt anzulegen. Anders als beim Endpunkt `POST products/{productId}/variantAttributes`, der automatisch alle möglichen Kombinationen aus den angegebenen Attributen generiert, werden hier nur die explizit übermittelten Kombinationen erzeugt. Bereits existierende Kombinationen werden ignoriert. Bei Kollisionen wird ein entsprechender Fehlercode zurückgegeben. Optional können auch IDs übergeben werden. Der Endpunkt eignet sich besonders, wenn nicht alle theoretisch möglichen Kombinationen eines Produkts benötigt werden, sondern nur eine gezielte Auswahl. Für die Nutzung sind Schreibrechte für Produktvarianten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/11-1701/variants/manage ``` #### Request-Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "selections": [ { "größe": "M", "farbe": "rot" }, { "id": "443", "größe": "L", "farbe": "blau" }, ... ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "id": "42", "selection": { "größe": "M", "farbe": "rot" } }, { "id": "443", "selection": { "größe": "L", "farbe": "blau" } }, ... ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Produktvarianten. | | 400 Bad Request | | Der Request-Body konnte nicht geladen werden | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben.
    `selections` beinhaltet ungültige Attribut oder Attributwerte. | | 400 Bad Request | "duplicateEntry" | Eine übergebene Attributkombination existiert bereits als Produktvariante. | | 400 Bad Request | "missing" | `selections` fehlt im Request-Body. | | 400 Bad Request | "invalidFormat" | `selections` ist kein Array.
    Ein Element in `selections` ist kein JSON-Objekt.
    Ein Attributwert ist kein String. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request-Body angegeben. | | 404 Not Found | | Produkt mit `id`=`{productId}` wurde nicht gefunden | | 409 Conflict | "versionConflict" | Das Produkt wurde während des Generierens der Varianten verändert. | ### DELETE products//variants/ Mit diesem Endpunkt kann eine bestehende Produktvariante anhand von Produkt-ID und Varianten-ID gelöscht werden. Dies ist etwa dann sinnvoll, wenn bestimmte Kombinationen von Varianten (beispielsweise Größe und Farbe) nicht mehr angeboten werden sollen. Sowohl das übergeordnete Produkt als auch die Variante müssen existieren. Andernfalls wird ein entsprechender Fehler zurückgegeben. Für die Nutzung sind Löschberechtigungen für Produktvarianten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/11-1701/variants/1 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | -------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Produktvarianten. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben. | | 404 Not Found | | Produkt mit `id`=`{productId}` wurde nicht gefunden
    Produktvariante mit `id={variantId}` wurde nicht gefunden | ## Bulk-Methoden für Varianten In diesem Abschnitt werden die Bulk-Endpunkte beschrieben, mit denen mehrere Datensätze in einem einzigen Request abgefragt oder verarbeitet werden können. ### POST bulk/products/variants Ermöglicht das massenhafte Erstellen und Aktualisieren von Produktdaten in einem einzigen Request. Der Request-Body ist ein JSON-Array, in dem jedes Element ein Produkt beschreibt. Erstell- und Schreibrechte für Produktvarianten sind erforderlich. Für jeden Eintrag wird die jeweilige Produktvariante über die Felder `productId`, `variantId` und `selection` identifiziert. Zum Aktualisieren einer Variante genügt `productId` in Kombination mit `selection` oder `variantId`. Beim Anlegen einer neuen Variante ist `selection` verpflichtend. Wird zusätzlich `variantId` mitgegeben, wird die neue Variante mit dieser ID erstellt. Standardmäßig werden nur Produktvarianten aktualisiert. Wird der Parameter createMissing=yes gesetzt, dann werden Produktvarianten in der Anfrage die noch nicht existieren automatisch neues angelegt. In einem Request können maximal 1000 Einträge verarbeitet werden. Dieses Limit gilt gemeinsam für **alle** Bulk-Endpunkte der API — siehe [API Basics – Bulk-Endpunkte](/schnittstellen/admin-interface-api/api-basics#bulk-endpunkte). #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/bulk/products/variants ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "custom": { "liste": [], "map": {} }, "productId": "144-46864", "selection": { "größe": "M", "farbe": "rot" } "id": "", "active": "always", "descr": "This is a new Variant", "name": "NewVariant", }, { "custom": { "liste": [], "map": {} }, "productId": "144-46864", "selection": { "größe": "L", "farbe": "blau" } "active": "always", "descr": "This is an existing Variant", "name": "existingVariant", } ] ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [{"lineNumber": 1, "productId": "144-46864", "variantId": "43"}], "skippedLines": [{ "lineNumber": 0, "productId": "144-46864", "errorType": "notFound", "fieldErrors": {} }] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen oder aktualisieren von Produkten. | | 400 Bad Request | | Der Request-Body konnte nicht geladen werden.
    Es wurden mehr als 1000 Einträge angegeben. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage oder ein ungültiger Subshop angegeben.
    Ein Feld enthält den Wert `null`.
    Ein Wert hat den Typ, der mit dem Typ aus der Konfiguration nicht übereinstimmt.
    Ein Preis-Wert kann nicht geparst werden.
    Ein Feld vom Typ `Map` hat einen Schlüssel, der kein String ist.
    Ein Feld vom Typ `List` ist kein Array von Strings.
    Ein Zeitwert ist nicht in ISO 8601 Format.
    Bild-Daten von einem Bild sind kein Array von Objekten.
    `id` des Formats oder `path` sind keine Strings. | | 400 Bad Request | "invalidCombination" | Es wurden `variantId` und `selection` angegeben, jedoch passt die `variantId` nicht zur über `selection` identifizierten Variante. | | 400 Bad Request | "invalidFormat" | `custom` ist kein Objekt. | | 400 Bad Request | "unknownDataField" | Ein nicht existierendes Produktdatenfeld wurde im Request-Body angegeben. | | 400 Bad Request | "notManualEditable" | Ein nicht bearbeitbares Produktdatenfeld wurde im Request-Body angegeben. | ## Methoden für Lagerbestand Allgemein Die folgenden Endpunkte ermöglichen das Abrufen, Erstellen, Aktualisieren und Löschen von Lagerbeständen im System. Jeder Lagerbestand wird durch eine eindeutige `inventoryId` identifiziert. Abhängig vom Endpunkt können Lagerbestände direkt gesetzt oder relativ verändert werden, beispielsweise beim Buchen von Zu- oder Abgängen. Für alle hier dokumentierten Endpunkte ist eine entsprechende Berechtigung für den Zugriff auf Lagerbestände erforderlich. Alle Endpunkte in diesem Abschnitt unterstützen den optionalen URL-Parameter `storageId`, mit dem die Lager-ID explizit angegeben werden kann. Wird dieser Parameter nicht gesetzt, wird automatisch die Lager-ID des aktiven Subshops verwendet. ### Woher kommt die `inventoryId`? Die `inventoryId` ist der Schlüssel des Lagerbestands-Eintrags. Beim Anlegen eines Produkts bzw. einer Variante legt das System automatisch einen Bestands-Eintrag mit einem **Standardschlüssel** an: | **Objekt** | **Standard-`inventoryId`** | **Beispiel** | | ---------------------- | --------------------------------------------------------------------------------------- | ------------ | | Produkt ohne Varianten | die Produkt-ID | `11-1701` | | Produktvariante | `{productId}.{variantId}` — Produkt-ID und Varianten-ID, getrennt durch einen **Punkt** | `11-1701.M` | Sie müssen die `inventoryId` also nicht separat abfragen, sondern können sie für den Standardfall aus Produkt- und Varianten-ID zusammensetzen. Der Standardschlüssel ist nur der **Ausgangswert**, keine Garantie. Die `inventoryId` eines Produkts kann überschrieben werden — genau dafür ist sie da: Mehrere Produkte oder Varianten können sich denselben Lagerbestand teilen, indem sie auf dieselbe `inventoryId` verweisen. Welche `inventoryId` einem Produkt tatsächlich zugeordnet ist, lesen Sie über [`GET products/{productId}/inventory`](#get-productsproductidinventory) im Feld `storeId`. Verlassen Sie sich in Integrationen, die auf gepflegten Shops arbeiten, nicht blind auf das Standardschema. Aus demselben Grund weichen die Beispiele in diesem Abschnitt (z. B. `11-1701 M`) vom Standardschema ab: Sie zeigen einen Shop, in dem eigene Bestandsschlüssel gepflegt wurden. ### GET products/inventory/ Mit diesem Endpunkt kann der Lagerbestand eines Produkts oder einer Produktvariante anhand der Lagerbestands-ID (`inventoryId`) abgerufen werden. Die Antwort enthält Informationen über den aktuellen Bestand, offene Bestellungen sowie den Zeitpunkt der letzten Aktualisierung. Damit der Endpunkt genutzt werden kann, müssen die entsprechenden Berechtigungen zum Lesen von Lagerbeständen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/inventory/11-1701%20M ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "amount": 10.0, "id": "100-21456", "openOrder": 0.0, "setAt": "2024-08-19T08:03:26.000Z", "updatedAt": "2024-08-19T08:03:26.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | -------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Lagerbeständen. | | 404 Not Found | | Es wurde kein Lagerbestand mit `id={inventoryId}` im aktuellen Subshop gefunden. | ### POST products/inventory Mit diesem Endpunkt wird ein neuer Lagerbestand für ein Produkt oder eine Produktvariante angelegt. Dabei wird eine eindeutige Lagerbestands-ID (`id`) sowie die verfügbaren und offenen Mengen angegeben. Damit dieser Endpunkt verwendet werden kann, müssen die entsprechenden Berechtigungen zum Erstellen von Lagerbeständen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/inventory ``` #### Request-Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "11-1701 M", "amount": 10.0, "openOrder": 0.0 } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "amount": 10.0, "id": "11-1701 M", "openOrder": 0.0, "setAt": "2025-05-01T10:12:00.000Z", "updatedAt": "2025-05-01T10:12:00.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Lagerbeständen. | | 400 Bad Request | | Der Request-Body konnte nicht geladen werden | | 400 Bad Request | "missing" | Das Pflichtfeld `id` fehlt im Request-Body | | 400 Bad Request | "invalidValue" | Das Feld `id` darf nicht leer sein | | 400 Bad Request | "invalidFormat" | Ein Feldwert hat einen falschen Datentyp, beispielsweise Number statt String für `id` | | 400 Bad Request | "unknownDataField" | Der Request-Body enthält ein unbekanntes Feld | | 400 Bad Request | "duplicateEntry" | Ein Lagerbestand mit der angegebenen `id` existiert bereits | ### PUT products/inventory/ Mit diesem Endpunkt aktualisieren Sie den Lagerbestand eines bestimmten Produkts anhand der übergebenen Parameter. Dabei können Sie sowohl den Bestand (`amount`) als auch die Anzahl der offenen Bestellungen (`openOrder`) anpassen, entweder absolut oder relativ: * Ist `amountType` auf `relative` gesetzt, wird der aktuelle Lagerbestand um den angegebenen `amount` erhöht. Bei einem negativen Wert wird er verringert. Andernfalls wird der Lagerbestand auf den Wert von `amount` gesetzt. * Entsprechend funktioniert `openOrderType`. Ist dieser auf `relative` gesetzt, wird die Anzahl der offenen Bestellungen um `openOrder` erhöht oder bei negativem Wert verringert. Ohne `relative` wird `openOrder` direkt gesetzt. Existiert noch kein Lagerbestand für die angegebene `{inventoryId}`, kann über den optionalen URL-Parameter `createMissing=yes` automatisch ein neuer Eintrag angelegt werden. Um diesen Endpunkt verwenden zu können, benötigen Sie die Berechtigung zum Schreiben von Lagerbeständen. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/inventory/1 ``` #### Request-Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "amount": 10.0, "amountType": "absolute", "openOrder": -1.0, "openOrderType": "relative" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "amount": 15.0, "id": "11-1701 M", "openOrder": 4.0, "setAt": "2025-05-01T14:22:30.000Z", "updatedAt": "2025-05-01T14:22:30.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | --------------- | ------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Lagerbeständen. | | 400 Bad Request | | Der Request-Body konnte nicht geladen werden | | 400 Bad Request | "invalidFormat" | `amount` oder `openOrder` ist kein gültiger Number-Typ | | 404 Not Found | | Es wurde kein Lagerbestand mit `id={inventoryId}` im aktuellen Subshop gefunden und `createMissing` ist nicht `yes` | ### DELETE products/inventory/ Mit diesem Endpunkt löschen Sie den Lagerbestand eines Produkts für die angegebene `{inventoryId}` im aktuellen Subshop. Wenn kein entsprechender Eintrag existiert, wird ein Fehler zurückgegeben. Um diesen Endpunkt verwenden zu können, benötigen Sie die Berechtigung zum Löschen von Lagerbeständen. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/inventory/1 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | --------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Lagerbeständen. | | 404 Not Found | | Es wurde kein Lagerbestand mit `id={inventoryId}` im aktuellen Subshop gefunden | ### POST bulk/products/inventory Mit diesem Endpunkt können Sie mehrere Lagerbestände gleichzeitig aktualisieren. Die zu aktualisierenden Einträge werden als Array im Request-Body übergeben. Jeder Eintrag muss eine `id` (Lagerbestands-ID) enthalten. Für jeden Eintrag können sowohl der Bestand (`amount`) als auch die Anzahl der offenen Bestellungen (`openOrder`) angepasst werden, entweder absolut oder relativ: * Ist `amountType` auf `relative` gesetzt, wird der aktuelle Lagerbestand um den angegebenen `amount` erhöht. Bei einem negativen Wert wird er verringert. Andernfalls wird der Lagerbestand auf den Wert von `amount` gesetzt. * Entsprechend funktioniert `openOrderType`. Ist dieser auf `relative` gesetzt, wird die Anzahl der offenen Bestellungen um `openOrder` erhöht oder bei negativem Wert verringert. Ohne `relative` wird `openOrder` direkt gesetzt. * Existiert noch kein Lagerbestand für eine angegebene `id`, kann über den optionalen URL-Parameter `createMissing=yes` automatisch ein neuer Eintrag angelegt werden. Einträge mit ungültigen Daten werden übersprungen, beispielsweise wenn `amount` kein Number-Typ ist. Um diesen Endpunkt verwenden zu können, benötigen Sie die Berechtigung zum Schreiben von Lagerbeständen. Der Endpunkt erwartet **POST** – auch wenn er bestehende Bestände aktualisiert. Das gilt für alle Bulk-Endpunkte. Ein `PUT` auf `bulk/products/inventory` wird nicht beantwortet: Der Request läuft ins Leere, ohne dass Bestände geändert werden. In einem Request können maximal 1000 Einträge verarbeitet werden. Dieses Limit gilt gemeinsam für **alle** Bulk-Endpunkte der API — siehe [API Basics – Bulk-Endpunkte](/schnittstellen/admin-interface-api/api-basics#bulk-endpunkte). #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/bulk/products/inventory?createMissing=yes ``` #### Request-Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "id": "11-1701 M", "amount": 10.0, "amountType": "absolute", "openOrder": -1.0, "openOrderType": "relative" }, { "id": "11-1702 L", "amount": 5.0 } ] ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": ["11-1701 M", "11-1702 L"], "skippedLines": [] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | --------------- | ------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Lagerbeständen. | | 400 Bad Request | | Der Request-Body konnte nicht geladen werden.
    Es wurden mehr als 1000 Einträge angegeben. | | 400 Bad Request | "invalidFormat" | Der URL-Parameter `stageId` ist ungültig. | ## Methoden für Produkte Lagerbestand Über die folgenden Endpunkte lassen sich lagerbezogene Einstellungen für einzelne Produkte verwalten. Dazu zählen sowohl die Zuordnung zu einem Lagerbestandseintrag als auch die Konfiguration der Darstellung im Shop, beispielsweise farbliche Ampellogik, individuelle Lagermeldungen und Reservierungszeiten. Die Einstellungen greifen dabei direkt auf die allgemeinen Lagerbestände zu, die über die Endpunkte im Abschnitt [Methoden für Lagerbestand Allgemein](#methoden-für-lagerbestand-allgemein) gepflegt werden. Für den Zugriff auf diese Endpunkte sind Lese- oder Schreibrechte für Produktdaten erforderlich, je nach gewählter Operation. ### GET products//inventory Mit diesem Endpunkt können Sie die Lagerbestandskonfiguration eines bestimmten Produkts abrufen. Diese Konfiguration umfasst unter anderem Schwellwerte für Ampelfarben, individuelle Lagermeldungen und die Reservierungsdauer. Die Angabe `storeId` verweist auf einen allgemeinen Lagerbestandseintrag, wie er über die Lagerbestands-Endpunkte verwaltet wird. Für die Verwendung dieses Endpunkts sind Lese-Berechtigungen für Produktdaten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/11-703/inventory ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "greenYellowBorder": 0, "messageLimit": 5, "messageMail": "m.mustermann@websale.de", "messageMode": "inactive", "redOrder": true, "reservationTime": 10, "state": "dynamic", "storeId": "11-1701%20M", "textGreen": "auf Lager", "textRed": "Wieder vorrätig in 1 Woche(n)", "textYellow": "Geringe Stückzahl", "useGlobalBorders": false, "useGlobalReservationTime": true, "useGlobalTexts": true, "yellowRedBorder": 0 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Produktdaten. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben. | | 404 Not Found | | Das Produkt mit `id={productId}` wurde nicht gefunden
    Kein Lagerbestand ist dem Produkt mit `id`=`{productId}` zugewiesen | ### PUT products//inventory Dieser Endpunkt dient dazu, die Lagerbestandseinstellungen eines Produkts zu aktualisieren. Dabei lassen sich beispielsweise die Darstellung im Shop (Ampel-Logik), Lagermeldungen oder die Reservierungszeit anpassen. Die Einstellung `storeId` bleibt hierbei unverändert und muss nicht übergeben werden. Für die Verwendung dieses Endpunkts sind Schreib-Berechtigungen für Produktdaten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/11-703/inventory ``` #### Request-Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "greenYellowBorder": 0, "messageLimit": 5, "messageMail": "m.mustermann@websale.de", "messageMode": "inactive", "redOrder": true, "reservationTime": 10, "state": "dynamic", "textGreen": "auf Lager", "textRed": "Wieder vorrätig in 1 Woche(n)", "textYellow": "Geringe Stückzahl", "useGlobalBorders": false, "useGlobalReservationTime": true, "useGlobalTexts": true, "yellowRedBorder": 0 } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "greenYellowBorder": 0, "messageLimit": 5, "messageMail": "m.mustermann@websale.de", "messageMode": "inactive", "redOrder": true, "reservationTime": 10, "state": "dynamic", "storeId": "11-1701%20M", "textGreen": "auf Lager", "textRed": "Wieder vorrätig in 1 Woche(n)", "textYellow": "Geringe Stückzahl", "useGlobalBorders": false, "useGlobalReservationTime": true, "useGlobalTexts": true, "yellowRedBorder": 0 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Produktdaten. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben
    `state` ∉ `{“dynamic”, “green”, “yellow”, “redhard”, “redsoft”}`
    `messageMode` ∉ `{“inactive”, “active”, “global”}` | | 400 Bad Request | "invalidFormat" | Ein Feldwert hat einen falschen Datentyp, beispielsweise String statt Boolean oder Number | | 400 Bad Request | | Der Request-Body konnte nicht geladen werden | | 404 Not Found | | Das Produkt mit `id={productId}` wurde nicht gefunden
    Kein Lagerbestand ist dem Produkt mit `id`=`{productId}` zugewiesen | | 503 Service Unavailable | | Versionskonflikte: Die Aktualisierung konnte nach mehreren Versuchen nicht durchgeführt werden. | ## Methoden für Varianten Lagerbestand Dieses Kapitel beschreibt die Endpunkte zur Verwaltung von lagerbezogenen Einstellungen einzelner Produktvarianten. Wie bei Produkten lassen sich auch für Varianten spezifische Lagerbestandsanzeigen, Ampelgrenzen, individuelle Texte und Reservierungszeiten festlegen. Die Zuordnung erfolgt ebenfalls über einen `storeId`, der auf einen zentral gepflegten Lagerbestand verweist. Für den Zugriff sind entsprechende Lese- oder Schreibrechte auf Produktdaten erforderlich. ### GET products//variants//inventory Ruft die Lagerbestandseinstellungen der Produktvariante mit der angegebenen `variantId` ab. Die Einstellungen beinhalten unter anderem Ampelgrenzen, Verfügbarkeitsanzeige, E-Mail-Benachrichtigungen sowie den Verweis (`storeId`) auf den zugehörigen zentralen Lagerbestand. Für diese Abfrage werden Lese-Rechte auf Produktvarianten benötigt. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/11-703/variants/1/inventory ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "greenYellowBorder": 0, "messageLimit": 5, "messageMail": "m.mustermann@websale.de", "messageMode": "inactive", "redOrder": true, "reservationTime": 10, "state": "dynamic", "storeId": "GUT", "textGreen": "auf Lager", "textRed": "Wieder vorrätig in 1 Woche(n)", "textYellow": "Geringe Stückzahl", "useGlobalBorders": false, "useGlobalReservationTime": true, "useGlobalTexts": true, "yellowRedBorder": 0 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Produktvarianten. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben. | | 404 Not Found | | Das Produkt mit `id={productId}` wurde nicht gefunden
    Die Produktvariante mit `id={variantId}` wurde nicht gefunden
    Kein Lagerbestand ist dem Produkt mit `id`=`{productId}` zugewiesen | ### PUT products//variants//inventory Aktualisiert die Lagerbestandseinstellungen der Produktvariante mit der angegebenen `variantId`. Die Konfigurationen wirken sich direkt auf die Darstellung im Shop aus und steuern beispielsweise die Verfügbarkeitsanzeige. Die Verknüpfung zum zentralen Lager erfolgt über das Feld `storeId`. Für diese Operation werden Schreibrechte auf Produktvarianten benötigt. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/11-703/variants/1/inventory ``` #### Request-Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "greenYellowBorder": 0, "messageLimit": 5, "messageMail": "m.mustermann@websale.de", "messageMode": "inactive", "redOrder": true, "reservationTime": 10, "state": "dynamic", "textGreen": "auf Lager", "textRed": "Wieder bestellbar in 1 Woche(n)", "textYellow": "Geringe Menge", "useGlobalBorders": false, "useGlobalReservationTime": true, "useGlobalTexts": true, "yellowRedBorder": 0 } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "greenYellowBorder": 0, "messageLimit": 5, "messageMail": "m.mustermann@websale.de", "messageMode": "inactive", "redOrder": true, "reservationTime": 10, "state": "dynamic", "textGreen": "auf Lager", "textRed": "Wieder bestellbar in 1 Woche(n)", "textYellow": "Geringe Menge", "useGlobalBorders": false, "useGlobalReservationTime": true, "useGlobalTexts": true, "yellowRedBorder": 0 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Produktvarianten. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben
    `state` ∉ `{“dynamic”, “green”, “yellow”, “redhard”, “redsoft”}`
    `messageMode` ∉ `{“inactive”, “active”, “global”}` | | 400 Bad Request | "invalidFormat" | Ein Feldwert hat einen falschen Datentyp, beispielsweise String statt Boolean oder Number | | 400 Bad Request | | Der Request-Body konnte nicht geladen werden | | 404 Not Found | | Das Produkt mit `id={productId}` wurde nicht gefunden
    Die Produktvariante mit `id={variantId}` wurde nicht gefunden
    Kein Lagerbestand ist dem Produkt mit `id`=`{productId}` zugewiesen | | 503 Service Unavailable | | Versionskonflikte: Die Aktualisierung konnte nach mehreren Versuchen nicht durchgeführt werden. | ## Methoden für Set-Produkte Dieses Kapitel beschreibt die Endpunkte zur Verwaltung von Set-Produkten (Produktbündeln). Für den Zugriff sind entsprechende Lese- oder Schreibrechte auf Produktdaten erforderlich. Der Preis eines Sets ist kein gespeicherter Wert. Er wird aus dem Preis des Hauptprodukts und den Preisen der Unterprodukte berechnet, und zwar jedes Mal neu. Wer ihn anzeigen will, ruft ihn über den Endpunkt [POST products/setproducts/preview](#post-productssetproductspreview) ab. Was das für bestehende Anbindungen bedeutet, steht am Ende dieses Kapitels im Abschnitt [Set-Preis wird nicht mehr gespeichert](#set-preis-wird-nicht-mehr-gespeichert). ### products//setproducts Gibt eine Liste mit Unterprodukten zurück, wenn das Produkt mit `id=parentProductId` einen Set besitzt. Optional kann `setParentProductList` IDs der Produkte enthalten, zu deren Sets das aktuelle Produkt gehört. Für diese Abfrage werden Lese-Rechte auf Produktdaten benötigt. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/12-2325/setproducts?subshopId=deutsch&from=0&size=100 ``` #### Antwort (Hauptprodukt) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "isChildProduct": false, "items": [ { "active": "always", "custom": { "brand": "", "commission": 0, "commissionTaxRate": "", "crossSelling": [], "customNumber": "", "ean": "", "filterField": "", "image": [], "isbn": "", "mainCategory": "", "metaDescription": "", "metaDescriptionSetManually": false, "metaTitle": "", "metaTitleSetManually": false, "multiProducts": "", "oneTimeFee": 0, "oneTimeFeeTaxRate": "", "productDiscount": 0, "productDiscountAbsolute": false, "productType": "", "robotsNoFollow": false, "robotsNoIndex": false, "validForDiscount": false, "video": "", "voucherProductActive": false, "voucherProductHtmlTemplate": "", "voucherProductPrice": false, "voucherProductTemplate": "", "weight": 0 }, "descr": "Beautiful! Mit unserer neuen, weißen Bluse mit femininen Volants an Kragen und Knopfleiste kreieren Sie im Nu lässig verspielte Looks. Das sportliche Feinoxford-Gewebe trägt sich sehr komfortabel und schmeichelt der Haut. Ein absolutes Must-have und Lieblingsteil für die neue Saison. Geschneidert in leicht taillierter Form (Regular Fit) mit verdeckter Knopfleiste und gerundeter Saumlinie. Länge ca. 68 cm.Farbe: Weiß.Original Herringbone. Reine Baumwolle.", "hasVariants": true, "id": "11-2492", "itemNumber": "11-2492", "name": "Rüschenbluse 'Florence'", "price": { "price": "69.900000", "scheduledPrices": [] }, "taxRateId": "1", "timestampCreatedAt": "2025-02-14T10:50:41.000Z", "timestampUpdatedAt": "2025-04-28T10:24:24.000Z" }, { "active": "always", "custom": { "brand": "", "commission": 0, "commissionTaxRate": "", "crossSelling": [], "customNumber": "", "ean": "", "filterField": "", "image": [], "isbn": "", "mainCategory": "", "metaDescription": "", "metaDescriptionSetManually": false, "metaTitle": "", "metaTitleSetManually": false, "multiProducts": "", "oneTimeFee": 0, "oneTimeFeeTaxRate": "", "productDiscount": 0, "productDiscountAbsolute": false, "productType": "", "robotsNoFollow": false, "robotsNoIndex": false, "validForDiscount": false, "video": "", "voucherProductActive": false, "voucherProductHtmlTemplate": "", "voucherProductPrice": false, "voucherProductTemplate": "", "weight": 0 }, "descr": "Schlichter Unterziehrolli? Von wegen! Dieses Basicteil werden Sie lieben, sobald Sie es das erste Mal getragen haben. Es ist aus besonders edlem Swiss Cotton Jersey gefertigt, einem sehr feinen, samtweichen und luxuriösen Jersey mit zartem Glanz. Auf der Haut fühlt er sich wahnsinnig gut an und durch seine Elastizität ist er unendlich bequem. Der etwas weiter geschnittene Rollkragen, wird locker drapiert und engt daher überhaupt nicht ein. Tragen Sie dieses Rollkragenshirt unter Blazern, Westen, Hemdjacken oder Blusen und Sie werden nicht nur top aussehen, sondern sich auch so fühlen! Normale Form (Regular Fit).Länge ca. 66 cm.Farbe: Ecru.Original Herringbone. Reine Baumwolle.", "hasVariants": true, "id": "11-2497", "itemNumber": "11-2497", "name": "Edles Rollkragenshirt", "price": { "price": "89.900000", "scheduledPrices": [] }, "taxRateId": "1", "timestampCreatedAt": "2025-02-14T10:50:43.000Z", "timestampUpdatedAt": "2025-04-28T10:24:24.000Z" } ], "setData": { "items": [ { "fixQuantity": false, "hidden": false, "id": "11-2497", "quantityFactor": 1, "usePrice": true }, { "fixQuantity": false, "hidden": false, "id": "11-2492", "quantityFactor": 1, "usePrice": true } ] }, "setParentProductList": [], "totalCount": 2 } ``` #### Antwort (Set-Unterprodukt) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "isChildProduct": true, "items": [], "setData": {}, "setParentProductList": [ "12-2325" ], "totalCount": 0 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ----------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Produktdaten. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben. | ### POST products//setproducts/assign Produkte aus dem Request Body werden dem Set vom Produkt mit `id=parentProductId` zugewiesen. Das Feld `prodId` kann entweder ein einzelner String oder ein Array von Strings sein. Für diese Abfrage werden Schreib-Rechte auf Produktdaten benötigt. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/11-2803/setproducts/assign?subshopId=deutsch ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "prodId": [ "105-59442" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | --------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Produktdaten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben. | | 400 Bad Request | "missing" | `prodId` fehlt oder ist leer. | | 400 Bad Request | "invalidFormat" | `prodId` ist kein Array von Strings. | | 400 Bad Request | "unknownDataField" | Der Request Body enthält unbekannte Felder. | | 404 Not Found | | `parentProductId` fehlt. | ### POST products//setproducts/update/ Daten vom Produkt mit `id=childProductId` im Set vom Produkt mit `id=parentProductId` werden aktualisiert. Für diese Abfrage werden Schreib-Rechte auf Produktdaten benötigt. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/12-2325/setproducts/update/11-2492?subshopId=deutsch ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "setData": { "id": "11-2492", "quantityFactor": 1, "usePrice": true, "fixQuantity": false, "hidden": false } } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "parentProductId": "12-2325", "childProductId": "11-2492", "setData": { "id": "11-2492", "quantityFactor": 1, "usePrice": true, "fixQuantity": false, "hidden": false } } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | --------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Produktdaten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben. | | 400 Bad Request | "missing" | `setData` fehlt im Request Body. | | 400 Bad Request | "invalidFormat" | `setData` ist kein Objekt. | | 400 Bad Request | "unknownDataField" | Der Request Body enthält unbekannte Felder. | | 404 Not Found | | `parentProductId` oder `childProductId` fehlen. | ### POST products/setproducts/preview Dieser Endpunkt berechnet den Preis eines Set-Produkts aus den übergebenen Werten und gibt das Ergebnis zurück. Er speichert nichts. Damit lässt sich der Set-Preis bereits während der Bearbeitung anzeigen, also noch bevor das Produkt gespeichert wird. Berechnet werden zwei Werte. `setPrice` ist die Summe aus dem Preis des Hauptprodukts und den Preisen aller Unterprodukte mit `usePrice`. `setOrgPrice` ist die Summe aus dem Preis des Hauptprodukts und den Preisen aller Unterprodukte und dient als Referenzpreis. Die Preise werden zum aktuellen Zeitpunkt aufgelöst, aktive Aktionspreise fließen also in beide Werte ein. Für diese Abfrage werden Schreib-Rechte auf Produktdaten benötigt. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/setproducts/preview ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "parentPrice": 19.99, "setProducts": [ { "id": "P1", "usePrice": true, "quantityFactor": 2 }, { "id": "P2", "usePrice": false, "quantityFactor": 1 } ], "scheduledPrices": [ { "price": "14.99", "startDate": "2026-08-01T00:00:00.000Z", "endDate": "2026-08-31T23:59:59.000Z", "promotionInfo": "Sommeraktion", "validForDiscount": true } ], "fixQuantity": false, "hidden": false } ``` | **Parameter** | **Typ** | **Beschreibung** | | ------------------------------ | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `parentPrice` | `number` | Standardpreis des Hauptprodukts. Pflichtangabe. | | `setProducts` | `array` (object) | Liste der Unterprodukte. Pflichtangabe. | | `setProducts[].id` | `string` | ID des Unterprodukts. | | `setProducts[].usePrice` | `bool` | Gibt an, ob der Preis dieses Unterprodukts in `setPrice` einfließt. | | `setProducts[].quantityFactor` | `number` | Menge, mit der das Unterprodukt in das Set eingeht. | | `scheduledPrices` | `array` (object) | Geplante Aktionspreise des Hauptprodukts. Optional. Aufbau wie im Abschnitt [Zeitgesteuerte Preise (Aktionspreise)](#zeitgesteuerte-preise-aktionspreise) beschrieben. | | `fixQuantity` | `bool` | Optional. Gilt für alle Unterprodukte gemeinsam, nicht je Unterprodukt. | | `hidden` | `bool` | Optional. Gilt für alle Unterprodukte gemeinsam, nicht je Unterprodukt. | Unbekannte IDs in `setProducts` werden übersprungen, ohne einen Fehler auszulösen. Ein Tippfehler in `setProducts[].id` führt deshalb nicht zu `404`, sondern zu einer Antwort mit einem zu niedrigen Preis. Prüfen Sie die IDs vor dem Aufruf. #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "setPrice": "29.97", "setOrgPrice": "39.96" } ``` Beide Werte sind Strings. Die Antwort im Beispiel ergibt sich aus einem Preis von 4,99 für `P1` und 9,99 für `P2`. `setPrice` enthält das Hauptprodukt und das zweifache `P1`, also 19,99 plus 9,98. In `setOrgPrice` kommt zusätzlich `P2` hinzu, weil dort alle Unterprodukte einfließen. Tragen alle Unterprodukte `usePrice`, sind beide Werte gleich. #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Produktdaten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "missing" | `parentPrice` oder `setProducts` fehlt. | | 400 Bad Request | "invalidFormat" | Ein Feld hat einen unpassenden Typ, beispielsweise `setProducts` als Objekt statt als Array. | | 400 Bad Request | "invalidValue" | Ein Eintrag in `scheduledPrices` ist ungültig. Die Fehlerschlüssel beschreibt der Abschnitt [Validierung und Fehlerschlüssel](#validierung-und-fehlerschlüssel). | **Entfallener Endpunkt.** Der bisherige Endpunkt `PUT products/{childProductId}/setproducts/recalculate` steht nicht mehr zur Verfügung. Er hat den Set-Preis berechnet und gespeichert. An seine Stelle tritt `POST products/setproducts/preview`, der ausschließlich berechnet. ### DELETE products//setproducts/ Das Produkt mit `id=childProductId` wird aus dem Set vom Produkt mit `id=parentProductId` entfernt. Gilt `childProductId=all`, werden alle Produkte aus dem Set entfernt. Gilt `parentProductId=all`, wird das Produkt mit `id=childProductId` aus allen Sets entfernt, in denen es enthalten ist. Für diese Abfrage werden Löschberechtigungen für Produktdaten benötigt. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/products/11-2527/setproducts/11-703 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Produktdaten. | | 400 Bad Request | "invalidValue" | Es wurde eine ungültige Stage angegeben. | | 404 Not Found | | `parentProductId` oder `childProductId` fehlen. | ### Set-Preis wird nicht mehr gespeichert Der Set-Preis ist kein gespeicherter Wert mehr, sondern wird bei Bedarf berechnet. Die impliziten Neuberechnungen beim Anlegen, Aktualisieren und Löschen von Produkten, bei den Bulk-Endpunkten und im Produktimport sind entfallen. Für Clients bedeutet das zwei Dinge. Erstens liefert kein Endpunkt mehr einen gespeicherten Set-Preis aus. Zweitens muss ein Client, der den Set-Preis anzeigen will, ihn über den Endpunkt [POST products/setproducts/preview](#post-productssetproductspreview) berechnen lassen. Im Shop wird der Set-Preis weiterhin bei jedem Seitenaufruf berechnet. Die Felder am Template-Objekt haben sich dabei geändert, `setPrice` und die zugehörigen Felder stehen nur noch an Set-Produkten. Was das für bestehende Templates bedeutet, beschreibt der Abschnitt [Änderungen an bestehenden Templates](/frontend/referenz/module/wsproducts#änderungen-an-bestehenden-templates). #### Entfernte Felder | **Feld** | **Ort** | **Auswirkung** | | ----------------- | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `setPrice` | Basisfeld eines Produkts | Erscheint nicht mehr in Produkt-Antworten und wird in Requests nicht mehr gelesen. Auch das Standard-Produktfeld in der Konfiguration ist entfallen. | | `setOrgPrice` | Slot in `content.usedFields.products` | Der Slot ist aus dem Konfigurationsschema entfernt. | | `double_setPrice` | Elasticsearch-Mapping | Das Indexfeld ist entfernt. | Die Entfernung von `double_setPrice` betrifft alle Abfragen, Filter und Sortierungen, die dieses Indexfeld verwenden. Bestehende Anbindungen müssen vor dem Update geprüft und angepasst werden. ## Ergänzende Referenzen * [API-Referenz Bildkonverter](/schnittstellen/admin-interface-api/api-referenz-bildkonverter) * [API-Referenz Kategorien](/schnittstellen/admin-interface-api/api-referenz-kategorien) * [API-Referenz Konfiguration](/schnittstellen/admin-interface-api/api-referenz-konfiguration) * [API-Referenz Meta-Daten](/schnittstellen/admin-interface-api/api-referenz-meta-daten) * [API-Referenz SEO-URLs](/schnittstellen/admin-interface-api/api-referenz-seo-urls) * [content - Katalog (Kategorien & Produkte)](/konfiguration/content-katalog-kategorien-produkte) ## Hinweis zu Produktdatenfeldern Neue Produktdatenfelder (zusätzliche Eigenschaften, Attribute oder technische Felder) können nicht direkt über die Produkt-API erstellt werden. Die API dient ausschließlich dem Auslesen und Pflegen vorhandener Felder. Um neue Felder zu definieren, muss die Konfiguration im Knoten `content.customProductField` verwendet werden. → [content - Katalog (Kategorien & Produkte)](/konfiguration/content-katalog-kategorien-produkte) Dort lassen sich individuelle Felder mit Typ, Suchrelevanz, Pflichtstatus und Varianteneigenschaften anlegen. Sobald ein Feld dort konfiguriert wurde, steht es anschließend automatisch in der Produkt-API zur Verfügung, beispielsweise in `GET products` oder `POST products`. ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Reporter Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-reporter Daten wie Bestellungen oder Newsletter-Abonnenten über die Reporting-Endpunkte der Admin Interface API exportieren und den Status verfolgen. Die Reporting-API stellt für bestimmte Services die Möglichkeit bereit, Daten zu exportieren (z. B. Newsletter-Abonnenten oder Bestellungen). Der Export kann in unterschiedlichen Formaten erfolgen, abhängig vom jeweiligen Service. Außerdem liefert die API Statusinformationen über den Fortschritt des Exportprozesses. Die folgende Übersicht zeigt, welche Services aktuell unterstützt werden und wie die Status-Codes zu interpretieren sind. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | --------------- | ------------- | --------------------- | --------------------- | ------------------- | --------------------- | | **Export** | report/ | | | | | ## Allgemein ### Unterstützte Services und Formate Der Endpunkt `report/` stellt eine einheitliche Schnittstelle zur Verfügung, mit der sich Daten aus dem Shop-System exportieren lassen. Die API ermöglicht es, Exportprozesse gezielt zu starten, deren Fortschritt abzufragen und bei Bedarf abzubrechen. Aktuell wird die Exportfunktion für die folgenden Services unterstützt: | **Service** | **Unterstützte Formate** | | ---------------------- | ------------------------ | | `adminUser` | `json`, `csv` | | `category` | `json`, `csv` | | `customerAccount` | `json`, `csv` | | `dataFeed` | `json`, `csv` | | `dataFeedTemplate` | `json`, `csv` | | `inquiry` | `json`, `csv`, `xml` | | `inventory` | `json`, `csv` | | `order` | `json`, `xml` | | `newsletterSubscriber` | `json`, `csv` | | `product` | `json`, `csv` | | `productRating` | `json`, `csv` | | `seoViews` | `json`, `csv` | | `transaction` | `json`, `csv` | | `voucher` | `json`, `csv` | | `voucherPreset` | `json`, `csv` | | `voucherTemplate` | `json`, `csv` | ### Statuswerte des Exportprozesses Exportprozesse laufen asynchron im Hintergrund. Während des Exports wird der aktuelle `Reportstatus` fortlaufend aktualisiert. Der Status eines Exportvorgangs kann folgende Werte annehmen: | **Wert** | **Bezeichnung** | **Bedeutung** | | -------- | --------------- | ------------------------------------------------------ | | `0` | `Ready` | Der Exportprozess ist bereit zur Ausführung. | | `1` | `Starting` | Der Prozess wurde gestartet, aber noch nicht begonnen. | | `2` | `Running` | Der Export wird derzeit ausgeführt. | | `3` | `Paused` | Der Export ist derzeit pausiert. | | `4` | `Canceled` | Der Exportprozess wurde manuell abgebrochen. | | `5` | `Finished` | Der Export wurde erfolgreich abgeschlossen. | | `6` | `Error` | Beim Export ist ein Fehler aufgetreten. | ## Methoden für den Datenexport ### GET report/\{service}/status Mit diesem Endpunkt kann der aktuelle Status eines Exportprozesses abgefragt werden. Dies umfasst u. a. Fortschritt, Anzahl verarbeiteter Einträge, Start- und Endzeit sowie den Link zur exportierten Datei (sofern der Export abgeschlossen wurde). Für den Export müssen die Leseberechtigungen für den jeweiligen Service vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/report/order/status ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "duration": 0, "end": "", "fileName": "orders_947bbbc6b27914ea35c0.json", "fileUrl": "https://content..de/report/orders_947bbbc6b27914ea35c0.json", "hasProgress": false, "lastError": "", "percentage": 100, "processed": 4, "start": "2025-02-19T09:15:15.000000000Z", "status": 2, "total": 4 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | --------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Starten des Services. | | 400 Bad Request | | `service` ist unbekannt. | | 503 Service Unavailable | "internalError" | Redis hat keinen Status geliefert. | ### POST report/\{service}/start Mit diesem Endpunkt wird der Exportprozess für den angegebenen Service gestartet. Optional können Filter und das gewünschte Ausgabeformat (`json`, `csv` etc.) über Query-Parameter angegeben werden. Damit der Export ausgelöst werden kann, müssen die Leseberechtigungen für den jeweiligen Service vorhanden sein. Falls bereits ein Exportprozess für den Service läuft, wird dieser automatisch abgebrochen, bevor der neue Export gestartet wird. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/report/order/start?format=json&filter_gte[createdAt]=2024-11-01T00:00:00.000Z ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "duration": 0, "end": "", "fileName": "orders_947bbbc6b27914ea35c0.json", "fileUrl": "https://content..de/report/orders_947bbbc6b27914ea35c0.json", "hasProgress": false, "lastError": "", "percentage": 100, "processed": 4, "start": "2025-02-19T09:15:15.000000000Z", "status": 2, "total": 4 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen der Daten des Services. | | 400 Bad Request | | `service` ist unbekannt.
    Der Service unterstützt das `format` nicht. | | 503 Service Unavailable | "Service currently unavailable" | Der Exportprozess konnte nicht getriggert werden. | | 503 Service Unavailable | "internalError" | Redis hat keinen Status geliefert.
    Der Status konnte nicht in Redis aktualisiert werden.
    Der Status hat sich 10 Sekunden lang nicht geändert. | ### POST report/\{service}/pause Mit diesem Endpunkt kann ein laufender Exportprozess für den angegebenen Service pausiert werden. Um den Vorgang zu pausieren, müssen die Leseberechtigungen für den jeweiligen Service vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/report/order/pause ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "duration": 0, "end": "", "fileName": "orders_947bbbc6b27914ea35c0.json", "fileUrl": "https://content..de/report/orders_947bbbc6b27914ea35c0.json", "hasProgress": false, "lastError": "", "percentage": 100, "processed": 4, "start": "2025-02-19T09:15:15.000000000Z", "status": 3, "total": 4 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Starten des Services. | | 400 Bad Request | | `service` ist unbekannt. | | 404 Not found | | Der Prozess läuft nicht. | | 503 Service Unavailable | "internalError" | Redis hat keinen Status geliefert.
    Redis kann nicht erreicht werden.
    Der Prozess konnte nicht gestoppt werden. | ### POST report/\{service}/resume Mit diesem Endpunkt kann ein pausierter Exportprozess für den angegebenen Service fortgefahren werden. Um den Vorgang fortzufahren, müssen die Leseberechtigungen für den jeweiligen Service vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/report/order/resume ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "duration": 0, "end": "", "fileName": "orders_947bbbc6b27914ea35c0.json", "fileUrl": "https://content..de/report/orders_947bbbc6b27914ea35c0.json", "hasProgress": false, "lastError": "", "percentage": 100, "processed": 4, "start": "2025-02-19T09:15:15.000000000Z", "status": 2, "total": 4 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Starten des Services. | | 400 Bad Request | | `service` ist unbekannt. | | 404 Not found | | Der Prozess ist nicht pausiert worden. | | 503 Service Unavailable | "internalError" | Redis hat keinen Status geliefert.
    Redis kann nicht erreicht werden.
    Der Prozess konnte nicht gestoppt werden. | ### DELETE report/\{service}/cancel Mit diesem Endpunkt kann ein laufender Exportprozess für den angegebenen Service vorzeitig abgebrochen werden. Um den Vorgang zu beenden, müssen die Leseberechtigungen für den jeweiligen Service vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/report/order/cancel ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "duration": 0, "end": "2025-02-19T09:15:15.000000000Z", "fileName": "orders_947bbbc6b27914ea35c0.json", "fileUrl": "https://content..de/report/orders_947bbbc6b27914ea35c0.json", "hasProgress": false, "lastError": "", "percentage": 100, "processed": 4, "start": "2025-02-19T09:15:15.000000000Z", "status": 4, "total": 4 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Starten des Services. | | 400 Bad Request | | `service` ist unbekannt. | | 404 Not found | | Der Prozess läuft nicht. | | 503 Service Unavailable | "internalError" | Redis hat keinen Status geliefert.
    Redis kann nicht erreicht werden.
    Der Prozess konnte nicht gestoppt werden. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz SEO-URLs Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-seo-urls Suchmaschinenfreundliche URLs für Shop-Seiten über die Admin Interface API verwalten, manuell pflegen oder per Schema automatisch erzeugen. Mit dem Endpunkt `seo/urls/` stellen wir Ihnen eine Schnittstelle bereit, mit der Sie technische Namen der Shop-Seiten verbergen können und stattdessen klarere Bezeichnungen zu benutzen. Diese können manuell gesetzt oder nach einem Schema generiert werden. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | ---------------------------- | ------------- | --------------------- | --------------------- | --------------------- | --------------------- | | **SEO-URLs der Shop-Seiten** | seo/urls/ | | | | | ### Datenfelder | **Name** | **Typ** | **Verwendung** | | --------------------------------------- | ------- | ---------------------------------------------------------------------- | | **path** | String | Pfad zur Ausgabe der URL | | **main** | Boolean | Gibt an, ob die URL in der aktuellen Version des Shops verwendet wird. | | **manual** | Boolean | Gibt an, ob die URL manuell gesetzt wurde. | | **name (bei Kategorien und Produkten)** | String | Der Name der Kategorie bzw. des Produkts | | **resourceIdentifier** | String | Seitenname oder Identifikator für eine Kategorie/ein Produkt | | **updatedAt** | String | Zeitpunkt der letzten Aktualisierung (ISO 8601-Format, UTC) | | **createdAt** | String | Zeitpunkt der Erstellung (ISO 8601-Format, UTC) | #### Beispiel (Produkt) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2024-06-13T12:12:53.000Z", "main": 1, "manual": 0, "path": "/Bekleidung/Damen_NOOS_High-Waist_Curvy_Skinny_Jeans", "resourceIdentifier": "100-69659", "updatedAt": "2024-06-13T12:12:53.000Z" } ``` #### Beispiel (Kategorie) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-04-28T11:20:45.000Z", "main": 1, "manual": 1, "name": "Elektronik & Computer", "path": "/Elektronik-Computer", "resourceIdentifier": "101-64607", "updatedAt": "2025-04-28T11:20:45.000Z" } ``` #### Beispiel (Shop-Seite) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-05-06T08:16:05.000Z", "main": 1, "manual": 1, "path": "/checkout", "resourceIdentifier": "checkout.htm", "updatedAt": "2025-05-06T08:16:05.000Z" } ``` ## Verwendung der Methoden In diesem Abschnitt werden die verfügbaren Endpunkte zur Verwaltung von SEO-URLs beschrieben. Sie ermöglichen das Abfragen, Erzeugen, Überprüfen, Aktualisieren und Löschen von SEO-URLs für Kategorien, Produkte und Templates im Shop-System. Die Nutzung dieser Methoden erfordert entsprechende Berechtigungen für das Lesen oder Bearbeiten von SEO-Daten. ### GET seo/urls/generate/status Dieser Endpunkt dient dazu, den aktuellen Status der Generierung von SEO-URLs zu überprüfen. Er gibt an, ob aktuell ein Generierungsprozess läuft (`"running": true`) oder bereits abgeschlossen ist (`"running": false`). Dies ist insbesondere hilfreich, wenn nach dem Start eines Generierungsvorgangs auf dessen Abschluss gewartet werden soll, bevor weitere Schritte erfolgen. Für die Nutzung dieses Endpunkts sind entsprechende Leseberechtigungen für SEO-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/urls/generate/status ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "running": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | -------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von SEO-Daten. | ### GET seo/urls/categories Der Endpunkt `GET seo/urls/categories` gibt eine Liste von SEO-URLs für Kategorien zurück. Die Liste kann über Sortier- und Filterparameter eingeschränkt werden. Der optionale Parameter `size` bestimmt die Anzahl der zurückgegebenen Ergebnisse und muss im Bereich von 1 bis 300 liegen. Für die Nutzung dieses Endpunkts sind entsprechende Berechtigungen zum Lesen von SEO-Daten erforderlich. #### Beispiel Das Beispiel ruft alle SEO-URLs, die zurzeit im Shop verwendet werden und nicht nur gültig sind (`main = 1`), von Kategorien ab und sortiert die Ergebnisse aufsteigend nach dem Feld `resourceIdentifier`. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/urls/categories?sort=resourceIdentifier:asc&filter_eq[main]=1 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": false, "items": [ { "createdAt": "2024-11-15T10:20:10Z", "index": 0, "name": "Neue Kategorie", "path": "/Neue_Kategorie-154", "resourceIdentifier": "1000-85809", "status": "test", "updatedAt": "2024-11-15T10:20:10Z" }, ... ], "nextPageToken": "MTAw", "totalCount": 262 } ``` #### Filterfelder `createdAt`, `updatedAt`, `resourceIdentifier`, `path`, `manual`, `main` #### Sortierfelder `createdAt`, `updatedAt`, `resourceIdentifier`, `path`, `main` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | -------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von SEO-Daten. | | 400 Bad Request | "invalidValue" | `size` ∉ \[1;300]
    `pageToken` ist ungültig. | | 400 Bad Request | "invalidCharacters" | | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | ### GET seo/urls/products Dieser Endpunkt liefert eine Liste aller SEO-URLs von Produkten. Mithilfe von optionalen Parametern können die Ergebnisse gefiltert und sortiert werden, z. B. nach Erstellungsdatum oder nach Produkt-ID. Der Parameter `size` steuert die Anzahl der Einträge pro Seite und muss im Bereich 1–300 liegen. Für den Zugriff werden entsprechende Leserechte für SEO-Daten benötigt. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/urls/products?sort=resourceIdentifier:asc ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "createdAt": "2024-11-15T10:20:10Z", "index": 1, "name": "Something", "path": "/MyCategory/Something", "resourceIdentifier": "100-41232", "status": "never", "updatedAt": "2024-11-15T10:20:10Z" }, ... ], "nextPageToken": "Mzg", "totalCount": 39 } ``` #### Filterfelder `createdAt`, `updatedAt`, `resourceIdentifier`, `path`, `manual`, `main` #### Sortierfelder `createdAt`, `updatedAt`, `resourceIdentifier`, `path`, `main` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | -------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von SEO-Daten. | | 400 Bad Request | "invalidValue" | `size` ∉ \[1;300]
    `pageToken` ist ungültig. | | 400 Bad Request | "invalidCharacters" | | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | ### GET seo/urls/templates Dieser Endpunkt ruft eine Liste der SEO-URLs für allgemeine Shop-Seiten (z. B. Login, Registrierung) ab. Die Ergebnisse lassen sich über optionale Parameter filtern und sortieren. Der Parameter `size` legt die maximale Anzahl an Ergebnissen pro Seite fest und muss im Bereich von 1 bis 300 liegen. Für den Zugriff sind entsprechende Leserechte für SEO-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/urls/templates?sort=resourceIdentifier:desc ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "createdAt": "2025-01-25T08:30:23Z", "index": 0, "path": "", "resourceIdentifier": "login.htm", "updatedAt": "2025-01-25T08:30:23Z" } ], "nextPageToken": "MA", "totalCount": 1 } ``` #### Filterfelder `createdAt`, `updatedAt`, `resourceIdentifier`, `path`, `manual`, `main` #### Sortierfelder `createdAt`, `updatedAt`, `resourceIdentifier`, `path`, `main` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | -------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von SEO-Daten. | | 400 Bad Request | "invalidValue" | `size` ∉ \[1;300]
    `pageToken` ist ungültig. | | 400 Bad Request | "invalidCharacters" | | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | ### POST seo/urls/check Dieser Endpunkt prüft, ob ein bestimmter SEO-Pfad (`seoPath`) bereits im System verwendet wird und liefert zusätzliche Informationen zur zugehörigen Ressource zurück. Damit lassen sich etwa potenzielle Kollisionen vor dem Speichern neuer URLs vermeiden. Die Nutzung erfordert Schreibrechte für SEO-Daten. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/urls/check ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "seoPath": "/neue_kategorie-176/" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "available": false, "main": true, "resourceIdentifier": "1001-26578", "viewController": "Category" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von SEO-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "missing" | `seoPath` wurde nicht übergeben. | | 400 Bad Request | "invalidFormat" | `seoPath` ist kein String. | | 400 Bad Request | "unknownDataField" | Es wurde ein unbekanntes Feld übergeben. | ### POST seo/urls/generate URLs werden erneut generiert. Optionaler Parameter `deleteOld` bestimmt, ob alle zurzeit nicht genutzte, aber noch gültige URLs gelöscht werden. Ob eine URL im Shop genutzt wird und nicht einfach nur gültig ist, bestimmt das Feld `main`. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/urls/generate ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "deleteOld": false } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von SEO-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | ### POST seo/urls/reset Dieser Endpunkt startet die (Re-)Generierung einer SEO-URL. Der alte Wert wird nicht gelöscht. Die Nutzung des Endpunkts erfordert Schreibrechte für SEO-Daten. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/urls/reset ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "viewControllerId": "Product", "resourceIdentifier": "139-55414" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true, "mainPath": "myURL" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von SEO-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "missing" | `viewControllerId` oder `resourceIdentifier` wurden nicht übergeben. | | 400 Bad Request | "invalidFormat" | `viewControllerId` oder `resourceIdentifier` ist kein String. | | 400 Bad Request | "unknownDataField" | Es wurde ein unbekanntes Feld übergeben. | ### PUT seo/urls Mit diesem Endpunkt können Sie eine neue SEO-URL erstellen oder eine bestehende URL aktualisieren. Dabei muss angegeben werden, welchem Controller (`viewControllerId`) und welchem Objekt (`resourceIdentifier`) die URL zugeordnet ist. Die URL wird über `optimalPathEsc` definiert. Der Endpunkt erfordert Schreibrechte für SEO-Daten. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/urls/ ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "viewControllerId": "Product", "resourceIdentifier": "100-41232", "optimalPathEsc": "/NewCategory/Something" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true, "mainPath": "/NewCategory/Something" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | -------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von SEO-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "missing" | `viewControllerId`, `resourceIdentifier` oder `optimalPathEsc` wurden nicht übergeben. | | 400 Bad Request | "invalidFormat" | `viewControllerId`, `resourceIdentifier` oder `optimalPathEsc` ist kein String. | | 400 Bad Request | "unknownDataField" | Es wurde ein unbekanntes Feld übergeben. | ### DELETE seo/urls Mit diesem Endpunkt kann eine bestehende SEO-URL entfernt werden. Nach dem Löschen ist die URL nicht mehr erreichbar, und es erfolgt keine automatische Weiterleitung mehr. Der Endpunkt setzt Löschberechtigungen für SEO-Daten voraus. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/seo/urls/ ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "seoPath": "/Neue_Kategorie/Neues_Produkt-7" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von SEO-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "missing" | `seoPath` wurde nicht übergeben. | | 400 Bad Request | "invalidFormat" | `seoPath` ist kein String. | | 400 Bad Request | "unknownDataField" | Es wurde ein unbekanntes Feld übergeben. | | 404 Not found | | Die URL wurde nicht gefunden. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Shop-Modi Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-shop-modi Über die Admin Interface API prüfen, ob ein Subshop alle Voraussetzungen für den Live-Modus erfüllt, bevor der Status final umgeschaltet wird. Über den Endpunkt `shopStatus/` wird eine Schnittstelle bereitgestellt, mit der sich vor dem Live-Schalten eines Subshops überprüfen lässt, ob alle Voraussetzungen dafür erfüllt sind. Die eigentliche Statusänderung erfolgt nicht über diesen Endpunkt, sondern als regulärer Schreibzugriff auf die Konfiguration. Eine fachliche Beschreibung der drei Modi und des Wechsels zwischen ihnen findet sich unter [Shop-Modi](https://dokumentation.websale.de/frontend/funktionsubersicht/inaktiv-seite). *** ## Unterstützte Methoden Angabe aller unterstützten Methoden | Befehl/Info | Endpunkte | DELETE | GET | POST | PUT | | -------------------- | ------------------------------- | ------------------- | --------------------- | ------------------- | ------------------- | | Bereitschaftsprüfung | `shopStatus/goLive/{subshopId}` | | | | | ## Methode für die Bereitschaftsprüfung Mithilfe der folgenden Methode wird geprüft, ob ein Subshop in den Aktiv-Modus wechseln darf. Sie ist rein lesend und nimmt keine Änderungen vor. Es werden alle aktiven Online-Zahlungsarten geprüft. Befindet sich eine dieser Zahlungsarten noch im Sandbox-Modus, wird sie als Blocker gemeldet. Für die Nutzung dieses Endpunkts ist eine gültige Anmeldung erforderlich. Eine servicespezifische Berechtigung wird nicht benötigt. ### GET shopStatus/goLive/\{subshopId} Prüft für den angegebenen Subshop, ob die Voraussetzungen für einen Wechsel in den Modus "Aktiv" erfüllt sind. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/shopStatus/goLive/deutsch ``` #### Antwort - Bereitschaft erfüllt ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "allowed": true } ``` #### Antwort - Blocker gefunden (Zahlungsmethode PayPal im Sandbox-Modus) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "allowed": false, "blockers": { "paypal": "sandbox" } } ``` #### Antwortfelder | Name | Typ | Bedeutung | | ---------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `allowed` | bool | `true`, wenn keine Blocker gefunden wurden und der Wechsel auf "Aktiv" zulässig ist.
    `false`, wenn Blocker gefunden wurden. | | `blockers` | object | Nur vorhanden, wenn `allowed = false`.
    Schlüssel: technischer Bezeichner der blockierenden Zahlungsart.
    Wert: Grund der Blockung (z.B. `sandbox`). | #### Fehlercodes | Fehler | Typ | Grund | | ---------------- | ------------------ | --------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert. Sie sind nicht angemeldet. | | 400 Bad Request | "invalidSubshopId" | Der angegebene Subshop existiert nicht. | **Setzen des Status**\ In dieser Schnittstelle gibt es keine eigene Methode zum Setzen des Status. Die Statusänderung erfolgt als regulärer Schreibzugriff auf den [Konfigurationsknoten](https://dokumentation.websale.de/konfiguration/general-allgemeine-shopeinstellungen#general-general-allgemeine-basiseinstellungen) mit dem Body `{ "data": { "status": "active" } }` . Siehe [API-Referenz Konfiguration](https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-konfiguration#get-config/nodes//overwrites). Beim Setzen des Status direkt über den Konfigurations-Endpunkt findet keine Bereitschaftsprüfung statt. Der Wechsel auf `active` wird auch dann übernommen, wenn aktive Online-Zahlungsarten noch im Sandbox-Modus laufen. Rufen Sie deshalb vor dem Setzen unbedingt die hier beschriebene GET-Methode auf, um die Prüfung nicht zu umgehen. # API-Referenz Sitemaps Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-sitemaps XML-Sitemaps über die Admin Interface API erstellen, anpassen, generieren und subshopbezogen mit Größen- und URL-Limits ausliefern lassen. Der Endpunkt `sitemaps/` stellt Ihnen eine Schnittstelle zur Verfügung, mit der Sie XML-Sitemaps in Ihrem Shop-System verwalten können. Über die API lassen sich neue Sitemaps erstellen, bestehende bearbeiten oder löschen sowie manuelle und geplante Generierungen durchführen. Zusätzlich ermöglicht die Schnittstelle das Abfragen von Statusinformationen zu vergangenen oder laufenden Generierungsvorgängen. Sitemaps können dabei individuell für bestimmte Subshops und auf Basis von frei definierbaren Vorlagen generiert werden. Die REST-API erlaubt eine präzise Steuerung über Parameter wie maximale Dateigröße oder maximale Anzahl von URLs pro Datei – so lässt sich die Auslieferung der Sitemaps gezielt optimieren. Die Nutzung dieser API erfordert entsprechende Berechtigungen für das Lesen, Schreiben oder Generieren von Sitemaps. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | ------------------------------------------------ | ------------------ | --------------------- | --------------------- | --------------------- | --------------------- | | [**Sitemaps**](#methoden-für-sitemaps) | sitemaps/ | | | | | | [**Sitemap-Vorlagen**](#methoden-für-vorlagen) | sitemaps/templates | | | | | | [**Protokolle**](#get-sitemapsprotocols) | sitemaps/protocols | | | | | | [**Generierung**](#methoden-für-die-generierung) | sitemaps/generate | | | | | ## Datenfelder ### Datenfelder der Sitemaps Sitemaps definieren, welche URLs eines Shops in welcher Form exportiert werden sollen. Sie basieren jeweils auf einer Sitemap-Vorlage und enthalten zusätzliche Parameter, z. B. zur Dateigröße, Anzahl der Einträge oder Subshop-Zuordnung. Sitemaps können für verschiedene Subshops erstellt werden und lassen sich zu definierten Zeiten automatisch exportieren. Die erzeugten Dateien werden standardmäßig im Verzeichnis `/sitemaps/` abgelegt. Sie sind öffentlich zugänglich und können z. B. über eine URL wie `www.ihre-shopdomain.de/sitemap.xml` aufgerufen werden. | **Name** | **Typ** | **Verwendung** | | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **id** | Integer | Eindeutige ID der Sitemap. | | **active** | Boolean | Gibt an, ob die Sitemap für den Export aktiv ist. | | **name** | String | Name der Sitemap. | | **fileName** | String | Name der Datei, die generiert wird. | | **subshopIds** | Array | Liste der Subshop-IDs für die Sitemap. Wenn leer, werden die Sitemaps für alle Subshops exportiert. | | **templateId** | Integer | Eindeutige ID der verwendeten Sitemap-Vorlage | | **maxFileSize** | Integer | Maximale Dateigröße einer Sitemap-Datei | | **maxFileEntries** | Integer | Maximale Anzahl der URLs in einer Sitemap-Datei | | **options** | Objekt | Zusätzliche Einstellungen (zurzeit nur `exportCharset`) | | **writeIntoRobots** | Boolean | Gibt an, ob ein Eintrag in die robots.txt-Datei geschrieben werden soll. | | **exportAfterImport** | Boolean | Gibt an, ob die Sitemap nach dem Import von Produktdaten exportiert werden soll. | | **exportPlan** | Array | Array von Ganzzahlen (Stunden), an denen Sitemaps exportiert werden. | | **exportStatus** | Integer | Status des Exportprozesses (z. B. beendet, beginnt, fehlgeschlagen)
    Mögliche Werte:
    `0 = Idle`
    `1 = Finished`
    `2 = Error`
    `3 = Starting`
    `4 = Running` | | **protocolId** | Integer | Eindeutige ID des Protokolls. | | **lastExportStarted** | String | Zeitpunkt des letzten Exportstarts. | | **lastExportFinished** | String | Zeitpunkt des letzten erfolgreichen Exports. | | **createdAt** | String | Zeitpunkt der Erstellung (ISO 8601-Format, UTC). | | **updatedAt** | String | Zeitpunkt der letzten Aktualisierung (ISO 8601-Format, UTC). | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "createdAt": "2025-03-19 11:06:47", "exportAfterImport": false, "exportPlan": [], "exportStatus": 1, "fileName": "sitemap121", "id": 129, "lastExportFinished": "0000-00-00 00:00:00", "lastExportStarted": "0000-00-00 00:00:00", "maxFileEntries": 50000, "maxFileSize": 52428800, "name": "sitemap1217", "options": { "exportCharset": "utf-8" }, "protocolId": 10, "subshopIds": [ "deutsch" ], "templateId": 3, "updatedAt": "2025-03-19 11:31:21", "writeIntoRobots": false } ``` #### Hinweise zur Aufteilung von Sitemaps Um die Ladezeit von Suchmaschinen zu optimieren und technischen Vorgaben gerecht zu werden, kann die Generierung von Sitemaps automatisch auf mehrere Dateien aufgeteilt werden. Dies geschieht, wenn eine der folgenden Grenzen überschritten wird: * Maximale Anzahl an URLs pro Datei: Standardmäßig 50.000 URLs * Maximale Dateigröße pro Datei: Standardmäßig 50 MB Diese Grenzen können über die Felder `maxFileEntries` und `maxFileSize` pro Sitemap individuell konfiguriert werden. Wird eine dieser Grenzen überschritten, erzeugt das System automatisch eine neue Sitemap-Datei mit einem fortlaufenden Zähler im Dateinamen. ### Datenfelder der Sitemap-Vorlagen Sitemap-Vorlagen (Templates) beschreiben die Struktur und den Inhalt einer Sitemap. Sie geben an, welche Ressourcen (z. B. Produkte, Kategorien oder Inhalte) exportiert werden und welche Felder dabei einbezogen werden sollen – etwa `loc`, `lastmod`, `priority` oder `changefreq`. Jede Sitemap muss auf einer Vorlage basieren. Änderungen an einer Vorlage beeinflussen alle Sitemaps, die darauf aufbauen. Auf diese Weise lassen sich verschiedene Exportkonfigurationen effizient wiederverwenden und zentral verwalten. | **Name** | **Typ** | **Verwendung** | | ------------- | ------- | ------------------------------------------------------------------------ | | **id** | Integer | Eindeutige ID der Sitemap-Vorlage | | **name** | String | Name der Sitemap-Vorlage | | **content** | String | Der Inhalt der Vorlage. Hier darf die Template-Sprache verwendet werden. | | **createdAt** | String | Zeitpunkt der Erstellung | | **updatedAt** | String | Zeitpunkt der letzten Aktualisierung | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "content": "{{ var $product = true }}\n{{ while($product) }}\n{{ $product = $wsProducts.loadNext() }}\n\n {{= $wsViews.url('Product', {productId: $product.id}, 'absolute') }}\n 2005-01-01\n monthly\n 0.8\n\n{{ /while }}", "createdAt": "2025-04-30 14:55:27", "id": 5, "name": "products", "updatedAt": "2025-04-30 14:55:27" } ``` ## Methoden für Sitemaps Über die folgenden Endpunkte können bestehende Sitemaps im System abgerufen, bearbeitet, erstellt oder gelöscht werden. Zusätzlich lassen sich Statusinformationen zum letzten Export sowie zugehörige Protokolle abfragen. Um diese Endpunkte zu nutzen, müssen entsprechende Berechtigungen für den Zugriff auf Sitemap-Daten vorhanden sein. ### GET sitemaps Mit dieser Methode können Sie eine Liste aller im System vorhandenen Sitemaps abrufen. Die Antwort enthält zu jeder Sitemap die zugehörigen Einstellungen sowie – falls bereits erfolgt – Informationen über erzeugte Dateien. Die Daten lassen sich nach verschiedenen Kriterien filtern oder sortieren, z. B. nach Subshop, Exportstatus oder Dateiname. Damit der Endpunkt verwendet werden kann, müssen entsprechende Berechtigungen zum Lesen von Sitemaps vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/sitemaps ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "filelist": [], "sitemap": { "active": true, "createdAt": "2025-02-14 11:11:53", "exportAfterImport": false, "exportPlan": [ 0 ], "exportStatus": 0, "fileName": "123", "id": 1, "lastExportFinished": "0000-00-00 00:00:00", "lastExportStarted": "0000-00-00 00:00:00", "maxFileEntries": 0, "maxFileSize": 0, "name": "123", "options": { "exportCharset": "utf-8" }, "protocolId": 0, "subshopIds": [ "deutsch", "english" ], "templateId": 1, "updatedAt": "2025-02-14 11:11:53", "writeIntoRobots": true }, "templateName": "1233122" }, ... ], "nextPageToken": "MQ", "totalCount": 2 } ``` #### Filterfelder `id`, `active`, `name`, `fileName`, `templateId`, `subshopIds`, `maxFileSize`, `maxFileEntries`, `exportAfterImport`, `exportStatus`, `lastExportStarted`, `lastExportFinished`, `createdAt`, `updatedAt` #### Sortierfelder `id`, `active`, `name`, `fileName`, `templateId`, `subshopIds`, `maxFileSize`, `maxFileEntries`, `exportAfterImport`, `exportStatus`, `lastExportStarted`, `lastExportFinished`, `createdAt`, `updatedAt` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | ------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Sitemaps. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET sitemaps/\{id} Mit dieser Methode kann ein einzelner Sitemap-Eintrag anhand seiner ID abgerufen werden. Die Antwort enthält sämtliche Konfigurationsdaten der Sitemap, einschließlich Subshop-Zuordnung, Exportstatus und Einstellungen zur Generierung. Damit der Endpunkt verwendet werden kann, müssen entsprechende Berechtigungen zum Lesen von Sitemaps vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/sitemaps/1 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "createdAt": "2025-02-14 11:11:53", "exportAfterImport": false, "exportPlan": [ 0 ], "exportStatus": 0, "fileName": "123", "id": 1, "lastExportFinished": "0000-00-00 00:00:00", "lastExportStarted": "0000-00-00 00:00:00", "maxFileEntries": 0, "maxFileSize": 0, "name": "123", "options": { "exportCharset": "utf-8" }, "protocolId": 0, "subshopIds": [ "deutsch", "english" ], "templateId": 1, "updatedAt": "2025-02-14 11:11:53", "writeIntoRobots": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Sitemaps. | | 400 Bad Request | "invalidValue" | `id` ist ungültig. | | 404 Not Found | | Sitemap mit `id`=`{id}` wurde nicht gefunden. | ### GET sitemaps/\{id}/status Mit dieser Methode kann der aktuelle Exportstatus einer bestimmten Sitemap abgefragt werden. Sie liefert pro Subshop den jeweiligen Status, etwa ob ein Export erfolgreich abgeschlossen wurde oder fehlgeschlagen ist. Obwohl der Endpunkt derzeit keine echten Prozesse verfolgt, stellt er strukturierte Statusdaten bereit. Damit der Endpunkt verwendet werden kann, müssen entsprechende Berechtigungen zum Lesen von Sitemaps vorhanden sein. #### **Beispiel** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/sitemaps/1/status ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "createdAt": "2025-02-21 08:43:42", "exportStatus": 2, "fileCount": 0, "fileName": "", "files": [], "id": 1, "lastExportError": "", "lastExportFinished": "0000-00-00 00:00:00", "lastExportStarted": "2025-02-21 08:47:58", "sitemapId": 1, "subshopId": "deutsch", "updatedAt": "2025-02-21 08:47:58" }, { "createdAt": "2025-02-21 08:43:42", "exportStatus": 2, "fileCount": 0, "fileName": "", "files": [], "id": 2, "lastExportError": "", "lastExportFinished": "0000-00-00 00:00:00", "lastExportStarted": "2025-02-21 08:47:58", "sitemapId": 1, "subshopId": "english", "updatedAt": "2025-02-21 08:47:58" } ] ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Sitemaps. | | 400 Bad Request | "invalidValue" | `id` ist ungültig. | | 404 Not Found | | Die Sitemap wurde nicht gefunden. | ### GET sitemaps/protocols Mit dieser Methode kann eine Liste aller Protokolleinträge für Sitemaps abgerufen werden. Die Protokolle enthalten Metainformationen zu vergangenen Exportvorgängen – etwa wann eine Sitemap exportiert wurde, welcher Subshop betroffen war und welchen Status der Export hatte. Um diesen Endpunkt nutzen zu können, müssen entsprechende Berechtigungen zum Lesen von Sitemaps vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/sitemaps/protocols ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "createdAt": "2025-02-21 08:43:42", "exportFinished": "0000-00-00 00:00:00", "exportStarted": "0000-00-00 00:00:00", "exportStatus": 1, "id": 1, "sitemapName": "my sitemap", "subshopData": [ { "createdAt": "", "exportError": "", "exportFinished": "0000-00-00 00:00:00", "exportStarted": "2025-02-21 08:43:42", "exportStatus": 2, "fileCount": 0, "fileName": "123.xml", "name": "", "subshopId": "deutsch", "updatedAt": "", "writeIntoRobots": false }, { "createdAt": "", "exportError": "", "exportFinished": "0000-00-00 00:00:00", "exportStarted": "2025-02-21 08:43:42", "exportStatus": 2, "fileCount": 0, "fileName": "123.xml", "name": "", "subshopId": "english", "updatedAt": "", "writeIntoRobots": false } ], "templateName": "defaultTemplate", "updatedAt": "2025-02-21 08:43:47" }, ... ], "nextPageToken": "NQ", "totalCount": 6 } ``` #### Filterfelder `id`, `sitemap`, `template`, `subshopIds`, `exportStatus`, `lastExportStarted`, `lastExportFinished`, `createdAt`, `updatedAt` #### Sortierfelder `id`, `sitemap`, `template`, `exportStatus`, `lastExportStarted`, `lastExportFinished`, `createdAt`, `updatedAt` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | ------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Sitemaps. | | 400 Bad Request | "invalidValue" | `size` ∉ \[1;300]
    `pageToken` ist keine Zahl oder kleiner als 0. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Filterwert ist ungültig. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### POST sitemaps Diese Methode ermöglicht das Erstellen eines neuen Sitemap-Eintrags mit allen relevanten Parametern wie Dateiname, Template-Zuweisung, Exportzeitpunkten und betroffenen Subshops. Damit diese Methode verwendet werden kann, müssen entsprechende Berechtigungen zum Erstellen von Sitemap-Daten vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/sitemaps ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "123", "fileName": "123", "writeIntoRobots": true, "active": true, "exportAfterImport": false, "templateId": 1, "subshopIds": [ "deutsch", "english" ], "exportPlan": [ 0 ], "maxFileSize": 0, "maxFileEntries": 0 } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "createdAt": "", "exportAfterImport": false, "exportPlan": [ 0 ], "exportStatus": 0, "fileName": "123", "id": 1, "lastExportFinished": "", "lastExportStarted": "", "maxFileEntries": 0, "maxFileSize": 0, "name": "123", "options": { "exportCharset": "utf-8" }, "protocolId": 0, "subshopIds": [ "deutsch", "english" ], "templateId": 1, "updatedAt": "", "writeIntoRobots": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Sitemaps. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | `templateId` ist ungültig. | | 400 Bad Request | "invalidFormat" | `name` oder `fileName` sind keine Strings.
    `active`, `exportAfterImport` oder `writeIntoRobots` sind keine Booleans.
    `templateId`, `maxFileEntries` oder `maxFileSize` sind keine Ganzzahlen.
    `exportPlan` ist kein Array von Ganzzahlen.
    `subshopIds` ist kein Array.
    `options` ist kein Objekt.
    `options.exportCharset` existiert und ist kein String. | | 400 Bad Request | "missing" | `name`, `active`, `fileName`, `templateId`, `exportAfterImport`, `exportPlan`, `maxFileEntries`, `maxFileSize`, `writeIntoRobots` oder `subshopIds` fehlen. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body übergeben. | | 400 Bad Request | "duplicateEntry" | Der neue Dateiname wurde schon verwendet. | ### PUT sitemaps/\{id} Diese Methode ermöglicht das Aktualisieren einer bestehenden Sitemap anhand ihrer eindeutigen ID. Es können sowohl technische Parameter (z. B. Dateiname, Template-Zuordnung, Exportoptionen) als auch organisatorische Einstellungen (z. B. betroffene Subshops, Zeitpläne) geändert werden. Damit diese Methode verwendet werden kann, müssen entsprechende Berechtigungen zum Schreiben von Sitemap-Daten vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/sitemaps/1 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "my sitemap", "fileName": "123", "writeIntoRobots": true, "active": true, "exportAfterImport": false, "templateId": 1, "subshopIds": [ "deutsch", "english" ], "maxFileEntries": 50000, "maxFileSize": 52428800, "exportPlan": [ 0 ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "createdAt": "2025-02-14 11:11:53", "exportAfterImport": false, "exportPlan": [ 0 ], "exportStatus": 0, "fileName": "123", "id": 1, "lastExportFinished": "0000-00-00 00:00:00", "lastExportStarted": "0000-00-00 00:00:00", "maxFileEntries": 50000, "maxFileSize": 52428800, "name": "my sitemap", "options": { "exportCharset": "utf-8" }, "protocolId": 0, "subshopIds": [ "deutsch", "english" ], "templateId": 1, "updatedAt": "2025-02-14 11:11:53", "writeIntoRobots": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Bearbeiten von Sitemaps. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | `id` ist ungültig.
    `templateId` ist ungültig. | | 400 Bad Request | "invalidFormat" | `name` oder `fileName` sind keine Strings.
    `active`, `exportAfterImport` oder `writeIntoRobots` sind keine Booleans.
    `templateId`, `maxFileEntries` oder `maxFileSize` sind keine Ganzzahlen.
    `exportPlan` ist kein Array von Ganzzahlen.
    `subshopIds` ist kein Array.
    `options` ist kein Objekt.
    `options.exportCharset` existiert und ist kein String. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body übergeben. | | 400 Bad Request | "duplicateEntry" | Der neue Dateiname wurde schon verwendet. | | 404 Not Found | | Sitemap mit `id`=`{id}` wurde nicht gefunden. | ### DELETE sitemaps/\{id} Diese Methode löscht eine bestehende Sitemap anhand ihrer ID dauerhaft aus dem System. Damit dieser Endpunkt genutzt werden kann, müssen entsprechende Berechtigungen zum Löschen von Sitemap-Daten vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/sitemaps/1 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | --------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Sitemaps. | | 400 Bad Request | "invalidValue" | `id` ist ungültig. | | 404 Not Found | | Sitemap mit `id`=`{id}` wurde nicht gefunden. | ## Methoden für Vorlagen Die folgenden Endpunkte ermöglichen das Verwalten von Sitemap-Vorlagen, auf deren Basis einzelne Sitemaps erzeugt werden. Eine Vorlage definiert den inhaltlichen Aufbau einer Sitemap und enthält typischerweise eine Schleife, die durch relevante Shop-Daten iteriert. Über die API können Vorlagen abgerufen, erstellt, aktualisiert und gelöscht werden. Um diese Funktionen nutzen zu können, müssen entsprechende Berechtigungen zum Lesen und Schreiben von Sitemaps vorhanden sein. ### GET sitemaps/templates Mit diesem Endpunkt kann eine Liste aller im System verfügbaren Sitemap-Vorlagen abgerufen werden. Diese Vorlagen definieren die Struktur und den Inhalt der später exportierten Sitemaps und dienen als Grundlage für die Generierung der XML-Dateien. Zur Nutzung des Endpunkts müssen die entsprechenden Berechtigungen zum Lesen von Sitemap-Daten vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/sitemaps/templates/ ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "content": "tre", "createdAt": "2025-02-14 11:11:53", "id": 1, "name": "1233122", "updatedAt": "2025-02-14 11:11:53" }, ... ], "nextPageToken": "MA", "totalCount": 1 } ``` #### Filterfelder `id`, `name`, `content`, `createdAt`, `updatedAt` #### Sortierfelder `id`, `name`, `content`, `createdAt`, `updatedAt` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | ------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Sitemaps. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET sitemaps/templates/\{id} Mit diesem Endpunkt kann eine einzelne Sitemap-Vorlage anhand ihrer ID geladen werden. Die Antwort enthält alle relevanten Informationen zur Vorlage, wie Name, Inhalt und Zeitstempel der letzten Änderungen. Für den Zugriff auf diesen Endpunkt sind entsprechende Berechtigungen zum Lesen von Sitemaps erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/sitemaps/templates/1 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "content": "something", "createdAt": "2025-02-14 11:11:53", "id": 1, "name": "1233122", "updatedAt": "2025-02-14 11:11:53" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Sitemaps. | | 400 Bad Request | "invalidValue" | `id` ist ungültig. | | 404 Not Found | | Sitemap-Vorlage mit `id`=`{id}` wurde nicht gefunden. | ### POST sitemaps/templates Mit diesem Endpunkt kann eine neue Sitemap-Vorlage erstellt werden. Die Vorlage enthält sowohl den Namen als auch das Template-Skript, mit dem die Inhalte der Sitemap generiert werden. Für das Anlegen neuer Vorlagen sind entsprechende Berechtigungen zum Erstellen von Sitemaps erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/sitemaps/templates ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "products", "content": "{{ var $product = true }}\n{{ while($product) }}\n{{ $product = $wsProducts.loadNext() }}\n\n {{= $wsViews.url('Product', {productId: $product.id}, 'absolute') }}\n 2005-01-01\n monthly\n 0.8\n\n{{ /while }}" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "content": "{{ var $product = true }}\n{{ while($product) }}\n{{ $product = $wsProducts.loadNext() }}\n\n {{= $wsViews.url('Product', {productId: $product.id}, 'absolute') }}\n 2005-01-01\n monthly\n 0.8\n\n{{ /while }}", "createdAt": "", "id": 5, "name": "products", "updatedAt": "" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | ----------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Sitemaps. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidFormat" | `name` oder `content` sind keine Strings. | | 400 Bad Request | "invalidValue" | `content` ist leer. | | 400 Bad Request | "missing" | `name` oder `content` fehlt. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body übergeben. | | 503 Service Unavailable | "internalError" | Das Erstellen vom Template ist fehlgeschlagen. | ### PUT sitemaps/templates/\{id} Über diesen Endpunkt kann eine bestehende Sitemap-Vorlage aktualisiert werden. Dabei lassen sich sowohl der Name als auch der Inhalt der Vorlage ändern. Änderungen an Vorlagen wirken sich auf die darauf basierenden Sitemaps aus, sobald diese neu generiert werden. Für die Nutzung dieses Endpunkts sind die entsprechenden Berechtigungen zum Bearbeiten von Sitemaps erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/sitemaps/templates/1 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "1233122", "content": "something new" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "content": "something new", "createdAt": "2025-02-14 11:11:53", "id": 1, "name": "1233122", "updatedAt": "2025-02-14 11:11:53" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Bearbeiten von Sitemaps. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | `id` ist ungültig.
    `content` ist leer. | | 400 Bad Request | "invalidFormat" | `name` oder `content` sind keine Strings. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body übergeben. | | 404 Not Found | | Die Vorlage wurde nicht gefunden, oder das Aktualisieren ist fehlgeschlagen. | ### DELETE sitemaps/templates/\{id} Dieser Endpunkt ermöglicht das Löschen einer bestehenden Sitemap-Vorlage anhand ihrer ID. Das Löschen ist nur möglich, wenn die entsprechende Vorlage existiert. Für diese Aktion müssen Berechtigungen zum Löschen von Sitemaps vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/sitemaps/templates/1 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | --------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Sitemaps. | | 400 Bad Request | "invalidValue" | `id` ist ungültig. | | 409 Conflict | | Die Vorlage wird noch von einer Sitemap verwendet und kann nicht gelöscht werden. | | 404 Not Found | | Vorlage mit `id`=`{id}` wurde nicht gefunden. | ## Methoden für die Generierung Diese Methoden ermöglichen die gezielte Steuerung der Generierung von Sitemaps. Je nach Anwendungsfall können einzelne Sitemaps direkt erzeugt, geplante Generierungen angestoßen oder Sitemaps nach dem Import von Produktdaten neu erstellt werden. Die Ausführung erfordert jeweils entsprechende Berechtigungen zum Veröffentlichen von Sitemaps. ### POST sitemaps/generate/hour/\{hour} Diese Methode startet die Generierung von Sitemaps, die zu einer bestimmten Stunde generiert werden müssen. Der Pfadparameter `{hour}` bestimmt die Stunde im 24-Stunden-Format (`0` bis `23`). Die Generierung erfolgt asynchron, das heißt, die Antwort enthält keine unmittelbaren Ergebnisse. Um diesen Endpunkt verwenden zu können, sind entsprechende Berechtigungen zum Veröffentlichen von Sitemaps erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/sitemaps/generate/hour/12 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------- | ----------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Veröffentlichen von Sitemaps. | | 404 Not Found | | Der Parameter `hour` fehlt oder ist ungültig. | | 503 Service Unavailable | "serviceUnavailable" | `FeedBuilderUrl` existiert nicht, oder die Generierung ist fehlgeschlagen. | ### POST sitemaps/generate/import Mit diesem Endpunkt werden alle Sitemaps generiert, die für den Export nach einem erfolgreichen Import von Produktdaten vorgesehen sind. Die Ausführung erfolgt asynchron und ohne Ergebnisinhalt in der Antwort. Um diesen Endpunkt verwenden zu können, müssen entsprechende Berechtigungen zum Veröffentlichen von Sitemaps vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/sitemaps/generate/import ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------- | ----------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Veröffentlichen von Sitemaps. | | 503 Service Unavailable | "serviceUnavailable" | `FeedBuilderUrl` existiert nicht, oder die Generierung ist fehlgeschlagen. | ### POST sitemaps/\{id}/generate Dieser Endpunkt startet die Generierung einer bestimmten Sitemap, die über ihre ID referenziert wird. Die Generierung erfolgt asynchron – das bedeutet, dass die Antwort keine fertige Datei zurückliefert, sondern lediglich den Start des Prozesses bestätigt. Um den Endpunkt nutzen zu können, sind entsprechende Berechtigungen zum Veröffentlichen von Sitemaps erforderlich. Optional kann über den Query-Parameter `subshopId` die Generierung auf bestimmte Subshops eingeschränkt werden. Der Parameter kann mehrfach angegeben werden, um mehrere Subshops auszuwählen. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/sitemaps/1/generate?subshopId=deutsch&subshopId=english ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------- | ----------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Veröffentlichen von Sitemaps. | | 400 Bad Request | "invalidValue" | `id` ist ungültig. | | 404 Not Found | | Sitemap mit `id`=`{id}` wurde nicht gefunden. | | 409 Conflict | | Sitemap ist inaktiv oder der Generierungsprozess wurde bereits gestartet. | | 503 Service Unavailable | "serviceUnavailable" | `FeedBuilderUrl` existiert nicht, oder die Generierung ist fehlgeschlagen. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Statistiken Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-statistiken Shop-Statistiken zu Bestellungen, Verkäufen, Anfragen, Bewertungen, Zahlungsarten und Zugriffen über die Admin Interface API abrufen. Der Endpunkt `statistics/` ermöglicht es Ihnen, verschiedene Statistiken Ihres Onlineshops in unserem Shop-System abzurufen. Mit der Schnittstelle ist es möglich, Statistiken zu Formularanfragen, Transaktionen und Zahlungsarten, Produktbewertungen, Bestellungen und Verkäufen und Zugriffsstatistiken abzufragen. ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | ---------------------- | ------------------------ | --------------------- | --------------------- | ------------------- | ------------------- | | **Anfragen** | statistics/inquiries | | | | | | **Bestellungen** | statistics/orders | | | | | | **Verkäufe** | statistics/sales | | | | | | **Newsletter** | statistics/newsletter | | | | | | **Produktbewertungen** | statistics/productrating | | | | | | **Transaktionen** | statistics/transactions | | | | | | **Zugriffe** | statistics/access | | | | | ## Datenpersistenz bei Statistiken Die Statistikdaten des Shop-Systems werden in drei verschiedenen Aggregationsstufen gespeichert: * **Stündliche Daten (pro Stunde)**\ Diese Daten liefern die feinste Detailtiefe und ermöglichen eine präzise Analyse von kurzfristigen Ereignissen, z. B. Peaks im Bestellverhalten während einer Werbeaktion.\ → *Speicherdauer: 3 Wochen*\ Danach werden die Daten automatisch gelöscht, um die Datenmenge zu begrenzen. * **Tägliche Daten (pro Tag)**\ Diese Aggregation eignet sich für mittel- bis langfristige Auswertungen, etwa zur Beobachtung von Wochentrends oder Kampagnenverläufen.\ → *Speicherdauer: 3 Monate* * **Monatliche Daten (pro Monat)**\ Diese Daten sind auf langfristige Analysen ausgerichtet, z. B. zur Bewertung saisonaler Schwankungen oder jährlicher Umsatzentwicklung.\ → *Speicherdauer: 3 Jahre* Diese gestaffelte Speicherung sorgt dafür, dass kurzfristig viele Details zur Verfügung stehen, während langfristig nur aggregierte Informationen erhalten bleiben. ## Ressourcen ### Datentabelle für Anfragen | **Name** | **Typ** | **Bedeutung** | | --------------------------------------- | ------- | ----------------------------------------------------------------------------------------------- | | **contact** (Bezeichnung des Formulars) | Objekt | Enthält Informationen zu dem Formular. | | **timestamp** | String | Zeitpunkt der Aggregation (z.B. der Anfang eines Monats oder eines Tages. ISO 8601-Format, UTC) | | **value** | Integer | Anzahl der Anfragen in dem jeweiligen Zeitintervall. | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "contact": [ { "timestamp": "2025-05-16T00:00:00.000Z", "value": 2 } ] } ``` ### Datentabelle für Bestellungen | **Name** | **Typ** | **Bedeutung** | | ----------------------- | ------- | ----------------------------------------------------------------------------------------------------- | | `accountTypeGuest` | Integer | Anzahl der Bestellungen, die von Gastkunden (ohne Kundenkonto) getätigt wurden. | | `accountTypeNew` | Integer | Anzahl der Bestellungen, die von neu registrierten Kunden getätigt wurden. | | `accountTypeRegistered` | Integer | Anzahl der Bestellungen von bestehenden registrierten Kunden. | | `amount` | Float | Gesamter Umsatz der Bestellungen ohne Gutscheine und Versandkosten. | | `amountTotal` | Float | Gesamter Umsatz inklusive aller Gutscheine und Versandkosten – der tatsächlich gezahlte Gesamtbetrag. | | `country` | String | Ländercode (z. B. „DE“, „AT“) der Bestellung, gemäß ISO 3166-1 Alpha-2. | | `currency` | String | Verwendete Währung der Bestellung, gemäß ISO 4217 (z. B. „EUR“, „USD“). | | `currencyIso` | String | ISO-4217-Code der Bestellwährung. | | `deviceTypeDesktop` | Integer | Anzahl der Bestellungen, die über ein Desktop-Gerät ausgelöst wurden. | | `deviceTypeMobile` | Integer | Anzahl der Bestellungen, die über ein mobiles Endgerät (Smartphone) getätigt wurden. | | `deviceTypeTablet` | Integer | Anzahl der Bestellungen, die über ein Tablet aufgegeben wurden. | | `feeTotalOrder` | Float | Gesamtsumme der Bestellgebühren, beispielsweise Zahlungsartgebühren. | | `itemsCount` | Integer | Gesamtanzahl der Artikel (Positionen) in den erfassten Bestellungen. | | `logDate` | String | Zeitpunkt der Datenaggregation (z.B. der Anfang eines Monats oder eines Tages. ISO 8601-Format, UTC). | | `ordersCount` | Integer | Gesamtanzahl der erfassten Bestellungen innerhalb des Zeitraums. | | `platformTypeApp` | Integer | Anzahl der Bestellungen, die über eine mobile App-Plattform getätigt wurden. | | `platformTypeWeb` | Integer | Anzahl der Bestellungen, die über die Webplattform (Browser) abgeschlossen wurden. | | `subshopId` | String | ID des Subshops, in dem die Bestellungen erfolgten. | | `totalDiscount` | Float | Gesamtsumme aller gewährten Rabatte über alle Bestellungen im Zeitraum. | | `voucherCount` | Integer | Anzahl der eingesetzten Gutscheine in allen Bestellungen. | | `voucherValue` | Float | Gesamter eingelöster Gutscheinwert über alle Bestellungen. | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountTypeGuest": 0, "accountTypeNew": 0, "accountTypeRegistered": 3, "amount": 15, "amountTotal": 17.9, "country": "DE", "currency": "€", "currencyIso": "EUR", "deviceTypeDesktop": 3, "deviceTypeMobile": 0, "deviceTypeTablet": 0, "itemsCount": 4, "logDate": "2025-05-20T14:00:00Z", "ordersCount": 3, "platformTypeApp": 0, "platformTypeWeb": 3, "subshopId": "deutsch", "totalDiscount": 0, "voucherCount": 1, "voucherValue": 8.95 } ``` ### Datentabelle für Verkäufe #### Für `GET statistics/sales` | **Name** | **Typ** | **Bedeutung** | | -------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------- | | `timestamp` | String | Zeitpunkt der Datenaggregation (z.B. der Anfang eines Monats oder eines Tages. ISO 8601-Format, UTC) | | `value.deutsch` (beliebige Subshop-ID) | Objekt | Enthält `sales` (Float, Umsatz im Subshop) und `currencyIso` (String, ISO-4217-Code der Subshop-Währung). | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "timestamp": "2025-04-22T22:00:00.000Z", "value": { "deutsch": { "sales": 1150.64, "currencyIso": "EUR" } } } ``` #### Für `POST statistics/sales/product` | **Name** | **Typ** | **Bedeutung** | | ----------- | ------- | --------------------------------------------- | | `logDate` | String | Zeitpunkt der Datenaggregation | | `productId` | String | Eindeutige ID des Produkts, das gekauft wurde | | `sales` | Integer | Anzahl an Verkäufen | | `subshopId` | String | Subshop, in dem das Produkt gekauft wurde | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "logDate": "2025-05-13 00:00:00", "productId": "143-68071", "sales": 1, "subshopId": "deutsch" } ``` ### Datentabelle für Newsletter | **Name** | **Typ** | **Bedeutung** | | ----------- | ------- | ---------------------------------------------------------------------------------------------------- | | `timestamp` | String | Zeitpunkt der Datenaggregation (z.B. der Anfang eines Monats oder eines Tages. ISO 8601-Format, UTC) | | `value` | Integer | Wert, der dem Zeitpunkt zugeordnet ist | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "timestamp": "2025-04-25T00:00:00.000Z", "value": 3 } ``` ### Statistiken für Transaktionen und Zahlungsarten | **Name** | **Typ** | **Bedeutung** | | ----------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **country** | String | Ländercode aus der Bestellung (ISO 3166-1 Alpha-2, z. B. "DE") | | **createdAt** | String | Zeitpunkt der Transaktion, ISO 8601, UTC. | | **currencyIso** | String | ISO-4217-Code der Transaktionswährung. | | **orderData** | Objekt | Enthält Bestelldaten | | **paymentMethod** | String | Bezeichnung der verwendeten Zahlungsart | | **paymentStatus** | Integer | Status der Zahlung.
    Mögliche Werte:
    `0 = Pending`
    `1 = Finished`
    `2 = Error`
    `3 = Redirected`
    `4 = Canceled`
    `5 = Rejected`
    `6 = CanceledByAdmin`
    `7 = Refunded`
    `8 = RefundedPartially` | | **subshopId** | String | Technische ID des betroffenen Subshops | | **total** | Float | Gesamtumsatz für diesen Datensatz (in der jeweiligen Währung) | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "computop-hosted": {}, "dummy": {}, "freeFields": { "agb.checked": "true", "agb.merchantText": "agb text here", "comment.text": "" }, "general": { "dateTime": "2025-04-23T08:26:14Z", "orderId": "531", "sessionId": "012bb5b99f69e976d4ae297ef1dcfdc59790d0ecb3756126b6f4fd08663c5790", "shopId": "test-mgoepfrich", "shopLanguage": "Deutsch", "subshopId": "deutsch", "testMode": false }, "order": { "currencyIso": "EUR", "currencySymbol": "€", "defaultTaxRate": "0.1900000", "delivererId": "dhl", "delivererOrderText": "DHL", "deliveryCost": "0.00", "deliveryTaxRate": "0.1900000", "paymentId": "bill", "paymentOrderText": "Rechnung", "priceType": "gross", "referer": "https://test-mgoepfrich.shop.websale.net/", "subreferer": "", "subtotal": "1055.67", "tax": "168.55", "total": "1055.67", "totalCommission": "0.00", "totalDiscount": "0.00", "totalVoucher": "0.00", "totalWeight": 0 }, "orderList": { "item": [ { "basketId": "a954f8529d0a00df2f84", "discount": "0.00", "extraFields": {}, "isAutoBasket": false, "isChangeable": true, "isRemovable": true, "isVisible": true, "itemNumber": "BD-0001", "name": "Damen NOOS High-Waist Curvy Skinny Jeans", "orgPrice": "0.00", "price": "31.99", "productId": "100-69659", "quantity": "33.00", "singleTotal": "31.99", "taxId": "19", "taxRate": "0.1900000", "total": "1055.67", "variantId": "2", "variantSelection": [ { "attributeId": "Größe", "optionId": "M" } ], "weight": 0 } ] }, "paypal-checkout": { "executePayPalResponse": "", "expressCheckout": "false", "orderID": "", "paymentAction": "CAPTURE", "paymentID": "", "paymentMode": "PayPal", "paypalStatus": "" }, "paypal-plus": {}, "shippingAddress": null, "vouchers": null } ``` ## Methoden für Anfragen ### GET statistics/inquiries Diese Methode liefert statistische Auswertungen zu den im Shop genutzten Anfragefunktionen (z. B. Kontaktformular, Rückrufservice, Reklamation etc.). Die Daten werden für jeden Subshop separat zurückgegeben und können stunden-, tage- oder monatsweise aggregiert werden. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Um die Daten abrufen zu können, müssen entsprechende Berechtigungen zum Lesen von Statistiken vorhanden sein. #### Beispiel Im gezeigten Beispiel werden die Anzahl der Anfragen im Zeitraum vom 29.02.2024 bis zum 28.02.2025 monatsweise ausgewertet - für die Subshops `deutsch` und `english`. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/inquiries/?from=2024-02-29T23:00:00.066Z&to=2025-02-28T22:59:59.066Z&aggregation=months&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=english ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "deutsch": { "contact": [ { "timestamp": "2024-10-01T00:38:42.000Z", "value": 4 } ] } } ``` #### Filterfelder `subshopID` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from`, `to` oder `aggregation` fehlen. | | 400 Bad Request | "invalidValue" | | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ### GET statistics/inquiries/duration Es werden die Bearbeitungszeiten der Anfragen geliefert. `value` gibt an, wie viele Tage für die Bearbeitung benötigt wurden. `count` gibt an, wie oft der Wert vorkommt. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Um die Daten abrufen zu können, müssen entsprechende Berechtigungen zum Lesen von Statistiken vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/inquiries/duration/?from=2024-02-29T23:00:00.353Z&to=2025-02-28T22:59:59.353Z&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=english ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "deutsch": { "contact": [ { "count": 2, "value": 3 } ], "productQuestion": [ { "count": 1, "value": 6 }, { "count": 1, "value": 13 } ] } } ``` #### Filterfelder `subshopID` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | ## Methoden für Bestellstatistiken ### POST statistics/orders/hours Dieser Endpunkt liefert stundenweise aggregierte Bestellstatistiken für den angegebenen Zeitraum. Im Request-Body können optional Subshops angegeben werden, um die Auswertung gezielt einzugrenzen. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/orders/hours?from=2025-04-30T22:00:00.000Z&to=2025-05-13T22:00:00.000Z ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "subshops": [ "deutsch", "englisch" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "accountTypeGuest": 0, "accountTypeNew": 0, "accountTypeRegistered": 1, "amount": 5, "amountTotal": 8.95, "country": "DE", "currency": "€", "currencyIso": "EUR", "deviceTypeDesktop": 1, "deviceTypeMobile": 0, "deviceTypeTablet": 0, "feeTotalOrder": 0.08, "itemsCount": 1, "logDate": "2025-05-20T14:00:00Z", "ordersCount": 1, "platformTypeApp": 0, "platformTypeWeb": 1, "subshopId": "deutsch", "totalDiscount": 0, "voucherCount": 0, "voucherValue": 0 } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ### POST statistics/orders/days Dieser Endpunkt liefert tageweise aggregierte Bestellstatistiken für den angegebenen Zeitraum. Im Request-Body können optional Subshops angegeben werden, um die Auswertung gezielt einzugrenzen. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/orders/days?from=2025-04-30T22:00:00.000Z&to=2025-05-13T22:00:00.000Z ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "subshops": [ "deutsch", "englisch" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "accountTypeGuest": 0, "accountTypeNew": 0, "accountTypeRegistered": 2, "amount": 66.98, "amountTotal": 66.98, "country": "DE", "currency": "€", "currencyIso": "EUR", "deviceTypeDesktop": 2, "deviceTypeMobile": 0, "deviceTypeTablet": 0, "feeTotalOrder": 6.98, "itemsCount": 2, "logDate": "2025-05-16T00:00:00Z", "ordersCount": 2, "platformTypeApp": 0, "platformTypeWeb": 2, "subshopId": "deutsch", "totalDiscount": 0, "voucherCount": 0, "voucherValue": 0 } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ### POST statistics/orders/months Dieser Endpunkt liefert monatsweise aggregierte Bestellstatistiken für den angegebenen Zeitraum. Im Request-Body können optional Subshops angegeben werden, um die Auswertung gezielt einzugrenzen. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/orders/months?from=2025-04-30T22:00:00.000Z&to=2025-05-13T22:00:00.000Z ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "subshops": [ "deutsch", "englisch" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "accountTypeGuest": 24, "accountTypeNew": 0, "accountTypeRegistered": 146, "amount": 23573.4, "amountTotal": 22705.61, "country": "DE", "currency": "€", "currencyIso": "EUR", "deviceTypeDesktop": 170, "deviceTypeMobile": 0, "deviceTypeTablet": 0, "feeTotalOrder": 235.73, "itemsCount": 311, "logDate": "2025-05-01T00:00:00Z", "ordersCount": 170, "platformTypeApp": 0, "platformTypeWeb": 170, "subshopId": "deutsch", "totalDiscount": 0, "voucherCount": 11, "voucherValue": 887.54 } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## Methoden für Verkäufe ### GET statistics/sales Dieser Endpunkt liefert die Umsätze im angegebenen Zeitraum, gruppiert nach Subshop und einem wählbaren Aggregationsintervall. Die Aggregation kann über den Parameter `aggregation` mit den Werten `minutes`, `hours`, `days`, `weeks`, `months`, `quarters` oder `years` erfolgen, optional zusätzlich mit `aggregationStep` als Vielfachem der gewählten Einheit. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. #### Beispiel Im gezeigten Beispiel wird der Umsatz im Zeitraum vom 22.04.2025 bis zum 28.04.2025 tagesweise aggregiert. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/sales?from=2025-04-22T22:00:00.000Z&to=2025-04-28T22:00:00.000Z&aggregation=days ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "timestamp": "2025-04-22T22:00:00.000Z", "value": { "deutsch": { "sales": 1150.64, "currencyIso": "EUR" } } }, { "timestamp": "2025-04-23T22:00:00.000Z", "value": {} }, { "timestamp": "2025-04-24T22:00:00.000Z", "value": { "deutsch": { "sales": 323.91, "currencyIso": "EUR" } } }, { "timestamp": "2025-04-25T22:00:00.000Z", "value": {} }, { "timestamp": "2025-04-26T22:00:00.000Z", "value": {} }, { "timestamp": "2025-04-27T22:00:00.000Z", "value": { "deutsch": { "sales": 183.92, "currencyIso": "EUR" } } } ] ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from`, `to` oder `aggregation` fehlen. | | 400 Bad Request | "invalidValue" | | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ### GET statistics/soldProducts Dieser Endpunkt liefert Verkaufszahlen im angegebenen Zeitraum, gruppiert nach Subshop und einem wählbaren Aggregationsintervall. Die Aggregation kann über den Parameter `aggregation` mit den Werten `minutes`, `hours`, `days`, `weeks`, `months`, `quarters` oder `years` erfolgen, optional zusätzlich mit `aggregationStep` als Vielfachem der gewählten Einheit. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. #### Beispiel Im gezeigten Beispiel werden die Verkaufszahlen im Zeitraum vom 02.07.2025 bis zum 30.09.2025 monatsweise aggregiert. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/soldProducts?from=2025-07-02T22:00:00.612Z&to=2025-09-30T21:59:59.612Z&aggregation=months ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "timestamp": "2025-07-02T00:00:00.000Z", "value": { "deutsch": 9 } }, { "timestamp": "2025-08-02T00:00:00.000Z", "value": { "deutsch": 15 } }, { "timestamp": "2025-09-02T00:00:00.000Z", "value": {} } ] ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from`, `to` oder `aggregation` fehlen. | | 400 Bad Request | "invalidValue" | | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ### POST statistics/sales/product Dieser Endpunkt liefert die Verkaufszahlen ausgewählter Produkte im angegebenen Zeitraum, gruppiert nach Datum und Subshop. Die Abfrage erfolgt durch Übergabe einer Liste von Produkt-IDs im Request Body. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/sales/product?from=2025-04-30T22:00:00.000Z&to=2025-05-13T22:00:00.000Z ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "productIds": [ "100-41232", "143-68071" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "logDate": "2025-05-13 00:00:00", "productId": "143-68071", "sales": 1, "subshopId": "deutsch" } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## Methoden für Newsletter-Statistiken ### GET statistics/newsletter/subscribed Dieser Endpunkt liefert die Anzahl neuer Newsletter-Abonnenten im angegebenen Zeitraum, gruppiert nach dem übergebenen Aggregationsintervall. Die Auswertung kann über den Filter `subshopId` auf einzelne Subshops eingeschränkt werden. Ohne den Parameter `filter_eq[subshopId]` werden alle Subshops berücksichtigt. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/newsletter/subscribed?from=2024-05-31T22:00:00.462Z&to=2025-05-31T21:59:59.462Z&aggregation=months&filter_eq[subshopId]=deutsch ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "timestamp": "2025-04-25T00:00:00.000Z", "value": 3 }, { "timestamp": "2025-04-29T00:00:00.000Z", "value": 4 } ] ``` #### Filterfelder `subshopId` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Der Parameter `aggregation` fehlt. | | 400 Bad Request | "invalidFormat" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 400 Bad Request | "invalidFormat" | | ### GET statistics/newsletter/unsubscribed Dieser Endpunkt liefert die Anzahl der Newsletter-Abmeldungen im angegebenen Zeitraum, gruppiert nach dem angegebenen Aggregationsintervall. Die Auswertung kann über den Filter `subshopId` auf bestimmte Subshops eingeschränkt werden. Ohne den Parameter `filter_eq[subshopId]` werden alle Subshops berücksichtigt. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/newsletter/unsubscribed?from=2025-04-12T22:00:00.926Z&to=2025-05-12T21:59:59.926Z&aggregation=days&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=englisch ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "timestamp": "2025-04-25T00:00:00.000Z", "value": 1 } ] ``` #### Filterfelder `subshopId` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Der Parameter `aggregation` fehlt. | | 400 Bad Request | "invalidFormat" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 400 Bad Request | "invalidFormat" | | ## Methoden für Statistiken der Produktbewertung ### POST statistics/productrating Dieser Endpunkt liefert alle erfassten Produktbewertungen im angegebenen Zeitraum, inklusive Bewertungstexten, Punkten, Genehmigungsstatus und weiteren Metadaten. Die Ergebnisse enthalten neben der Bewertung auch Informationen wie Subshop, Produkt-ID, Bewertungsersteller und eventuelle Händlerkommentare. Wenn das Feld `type` die Werte `1` (`MostRated`) oder `2` (`BestRated`) enthält, können auch die Durchschnittswerte und die Anzahl der Bewertungen vorkommen. Es ist möglich, nur bestimmte Subshops und bei `type=0` nur bestimmte Produkte zu berücksichtigen. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen zum Lesen von Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/productrating?from=2024-05-14T22:00:00.000Z&to=2025-05-15T10:49:09.230Z ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "subshops": [ "deutsch", "englisch" ], "limit": 5, "type": 2 } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "accountId": "37", "accountType": 2, "anonymous": false, "answeredAt": "2025-04-24 12:25:41", "approval": true, "avgRating": 4.5, "categoryId": "", "createdAt": "2025-04-23 12:52:14", "description": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Animi illum odit accusantium, ipsum pariatur laborum quos dolor nulla error deserunt placeat minima tempore vitae harum alias necessitatibus facere quae quidem!", "disapprovalReason": "", "id": 1, "merchantComment": "Das ist ein Test Kommentar.", "orderId": "536", "points": 4, "productId": "101-41470", "productType": "standard", "subject": "Lorem ipsum dolor sit amet consectetur", "subshopId": "deutsch" }, { "accountId": "39", "accountType": 2, "anonymous": false, "answeredAt": "", "approval": false, "avgRating": 4.7, "categoryId": "", "createdAt": "2025-04-23 13:13:49", "description": "cool", "disapprovalReason": "", "id": 2, "merchantComment": "", "orderId": "553", "points": 5, "productId": "101-41470", "productType": "standard", "subject": "oh yea", "subshopId": "deutsch" }, { "accountId": "37", "accountType": 2, "anonymous": true, "answeredAt": "2025-04-29 08:31:00", "approval": false, "avgRating": 3, "categoryId": "", "createdAt": "2025-04-24 12:39:19", "description": "asdfasdf Test 1233", "disapprovalReason": "Falsche angabe.", "id": 5, "merchantComment": "", "orderId": "557", "points": 3, "productId": "103-91837", "productType": "standard", "subject": "Verbesserung", "subshopId": "deutsch" }, ... ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ----------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte.
    Statistiken konnten nicht geladen werden. | ### POST statistics/productrating/average Dieser Endpunkt liefert den durchschnittlichen Bewertungswert aller erfassten Produktbewertungen im angegebenen Zeitraum. Die Auswertung umfasst alle Bewertungen über sämtliche Subshops hinweg. Wenn das Feld `"subshops"` übergeben wird, werden nur die aufgelisteten Subshops berücksichtigt. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen zum Lesen von Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/productrating/average?from=2024-05-14T22:00:00.000Z&to=2025-05-15T10:55:44.323Z ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "subshops": [ "deutsch", "englisch" ] } ``` #### Antwort `data` ist ein Float. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "data": 4.0 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ----------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte.
    Statistiken konnten nicht geladen werden. | ### POST statistics/productrating/count Dieser Endpunkt liefert die Gesamtanzahl aller erfassten Produktbewertungen im angegebenen Zeitraum. Die Zählung umfasst alle Bewertungen unabhängig von deren Freigabestatus. Wenn das Feld `"subshops"` übergeben wird, werden nur die aufgelisteten Subshops berücksichtigt. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen zum Lesen von Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/productrating/count?from=2024-05-14T22:00:00.000Z&to=2025-05-15T10:55:44.323Z ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "subshops": [ "deutsch", "englisch" ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "data": 4 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ----------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte.
    Statistiken konnten nicht geladen werden. | ### POST statistics/productrating/averagecount Dieser Endpunkt liefert den durchschnittlichen Bewertungswert pro Produkt im angegebenen Zeitraum. Die Auswertung umfasst alle Bewertungen über sämtliche Subshops hinweg. Wenn das Feld `"subshops"` übergeben wird, werden nur die aufgelisteten Subshops berücksichtigt. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen zum Lesen von Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/productrating/averagecount?from=2024-05-14T22:00:00.000Z&to=2025-05-15T10:55:44.323Z ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "subshops": [ "deutsch", "englisch" ] } ``` #### Antwort `data` ist ein Float. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "data": 1.3333 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ----------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte.
    Statistiken konnten nicht geladen werden. | ## Methoden für Transaktionen & Zahlungsarten ### GET statistics/transactions Dieser Endpunkt liefert eine Liste von Transaktionen mit detaillierten Bestell- und Zahlungsinformationen für den angegebenen Zeitraum, gruppiert nach dem gewählten Aggregationsintervall. Die Auswertung kann über den Filter `subshopId` auf einzelne Subshops eingegrenzt werden. Wenn gar keine Subshop-ID angegeben wird, werden keine Daten geliefert. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen zum Lesen von Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/transactions?from=2024-02-29T23:00:00.635Z&to=2025-02-28T22:59:59.635Z&aggregation=months&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=english ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "country": "Deutschland", "createdAt": "2024-10-10T12:00:00.000Z", "orderData": { ... }, "paymentMethod": "PayPal Checkout (PayLater)", "paymentStatus": 4, "subshopId": "deutsch", "total": 11 }, { "country": "Deutschland", "createdAt": "2024-10-10T12:00:00.000Z", "orderData": { ... }, "paymentMethod": "Rechnung", "paymentStatus": 1, "subshopId": "deutsch", "total": 11 }, ... ] } ``` #### Filterfelder `subshopID` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | Der Parameter `aggregation` fehlt oder enthält einen ungültigen Wert (nur `hours`, `days`, `months` erlaubt). | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ### GET statistics/transactions/tableData Dieser Endpunkt liefert eine tabellarische Übersicht der Umsätze, gruppiert nach Zahlungsart und Land, für den angegebenen Zeitraum. Die Daten sind nach Land sortiert und können zusätzlich über die Filter `subshopId` und `country` eingeschränkt werden. Wenn gar keine Subshop-ID oder gar kein Land angegeben wird, werden keine Daten geliefert. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Jeder Eintrag enthält zusätzlich `currencyIso`, den ISO-4217-Code der Währung von `total`. Für die Nutzung sind Leseberechtigungen zum Lesen von Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/transactions/tableData?size=100&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=english&filter_eq[country]=Deutschland&from=2025-05-09T22:00:00.681Z&to=2025-05-16T21:59:59.681Z&aggregation=days ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "country": "Deutschland", "paymentMethod": "PayPal Checkout", "total": 8.949999809265137, "currencyIso": "EUR" }, { "country": "Deutschland", "paymentMethod": "Sichere Zahlungsart", "total": 8.949999809265137, "currencyIso": "EUR" } ] } ``` #### Filterfelder `subshopID`, `country` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | Der Parameter `aggregation` fehlt oder enthält einen ungültigen Wert (nur `hours`, `days`, `months` erlaubt). | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ### GET statistics/transactions/countries Dieser Endpunkt liefert eine Liste aller Länder, aus denen im Shop Bestellungen getätigt wurden. Die zurückgegebenen Länderwerte können zur Filterung in anderen Transaktionsendpunkten verwendet werden. Für die Nutzung sind Leseberechtigungen zum Lesen von Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/transactions/countries ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": ["Deutschland"] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ### GET statistics/transactions/methods Dieser Endpunkt liefert eine Liste aller im Shop verwendeten Zahlungsarten, die in den Transaktionsdaten erfasst wurden. Die aufgeführten Zahlungsarten können zur Filterung in weiteren statistischen Auswertungen genutzt werden. Für die Nutzung sind Leseberechtigungen zum Lesen von Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/transactions/methods ``` ### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ "Min Rechnung", "PayPal Checkout", "PayPal Checkout (PayLater)", "Rechnung", "Sichere Zahlungsart", "Vorauskasse" ] } ``` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | # Methoden für Zugriffsstatistiken ## GET statistics/access/currentVisitors Dieser Endpunkt liefert die aktuelle Anzahl an Besuchern sowie die Vergleichszahl zum gleichen Zeitpunkt am Vortag. Die Auswertung kann über den Filter `subshopId` auf bestimmte Subshops eingeschränkt oder subshopübergreifend erfolgen. Ohne den Parameter `filter_eq[subshopId]` werden berücksichtigt. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/currentVisitors ``` ### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "numVisitors": 161, "numVisitorsYesterday": 50 } ``` ### Filterfelder `subshopID` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | ## GET statistics/access/visitors Dieser Endpunkt liefert die Anzahl der Besucher (ausschließlich menschlicher Nutzer) im angegebenen Zeitraum, gruppiert nach einem Aggregationsintervall. Die Auswertung kann über den Filter `subshopId` auf bestimmte Subshops eingeschränkt werden. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/visitors?from=2025-03-31T22:00:00.000Z&to=2025-07-31T21:59:59.000Z&aggregation=month&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=english ``` ### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 0, "key": 1740787200000, "key_as_string": "2025-03-01T00:00:00.000Z", "uniqueVisitors": { "value": 0 } }, { "count": 3212, "key": 1743465600000, "key_as_string": "2025-04-01T00:00:00.000Z", "uniqueVisitors": { "value": 1 } }, { "count": 9777, "key": 1746057600000, "key_as_string": "2025-05-01T00:00:00.000Z", "uniqueVisitors": { "value": 1 } }, { "count": 1346, "key": 1748736000000, "key_as_string": "2025-06-01T00:00:00.000Z", "uniqueVisitors": { "value": 1 } } ] } ``` ### Filterfelder `subshopID` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from`, `to` oder `aggregation` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/robots Dieser Endpunkt liefert die Anzahl der Zugriffe durch Suchmaschinen-Bots im angegebenen Zeitraum. Die Daten ermöglichen die Auswertung von Bot-Traffic auf dem Shop. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/robots?from=2025-05-19T12:58:15.873Z&to=2025-05-31T21:59:59.999Z ``` ### Antwort ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 5623 ``` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/all Dieser Endpunkt liefert die Gesamtanzahl der Besucher im angegebenen Zeitraum. Die Auswertung kann über den Filter `subshopId` auf bestimmte Subshops eingegrenzt werden. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/all?from=2025-05-08T22:00:00.795Z&to=2025-05-15T21:59:59.795Z&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=englisch ``` ### Antwort ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 171 ``` ### Filterfelder `subshopID` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/httpCodes Dieser Endpunkt liefert eine Übersicht, wie häufig bestimmte HTTP-Statuscodes im angegebenen Zeitraum aufgetreten sind, inklusive der zugehörigen Pfade. Die Daten ermöglichen eine gezielte Analyse der Systemantworten (z. B. 200, 301, 500) auf unterschiedliche Zugriffsanfragen. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/httpCodes?from=2025-05-01T07:51:51.600Z&to=2025-05-15T07:51:51.600Z ``` ### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 125742, "key": "200", "subStats": [ { "count": 86880, "key": "/" }, { "count": 364, "key": "/?wsvc=View&view=basket.htm" }, { "count": 308, "key": "/?wsvc=View&view=error.htm" }, { "count": 98, "key": "/?wsvc=Product&productId=140-23474" }, { "count": 97, "key": "/checkout?step=3&payDelivChange=true" }, ... ] }, { "count": 536, "key": "302", "subStats": [ { "count": 119, "key": "/?wsvc=View&view=basket.htm" }, { "count": 70, "key": "/checkout?step=3&payDelivChange=true" }, { "count": 63, "key": "/" }, { "count": 22, "key": "/Bekleidung/Damen_NOOS_High-Waist_Curvy_Skinny_Jeans?varid=2" }, { "count": 22, "key": "/checkout?step=2" }, ... ] }, { "count": 299, "key": "301", "subStats": [ { "count": 134, "key": "/robots.txt" }, { "count": 23, "key": "/favicon.ico" }, { "count": 9, "key": "/(Null)" }, { "count": 6, "key": "/checkout?step=3&payDelivChange=true" }, { "count": 3, "key": "/.env" }, { "count": 3, "key": "/_profiler/phpinfo" }, { "count": 2, "key": "/?wsvc=View&view=account%2femailVerify.htm" }, ... ] }, { "count": 2, "key": "500", "subStats": [ { "count": 2, "key": "/?wsvc=View&view=account%2fwatchlist.htm" } ] } ] } ``` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/os Dieser Endpunkt liefert eine Übersicht darüber, wie häufig bestimmte Betriebssysteme im angegebenen Zeitraum für Zugriffe auf den Shop verwendet wurden. Die Auswertung kann über die Filter `subshopId` und `device` gezielt auf einzelne Subshops und Gerätetypen eingeschränkt werden. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/os?from=2025-05-01T07:51:51.598Z&to=2025-05-15T07:51:51.598Z&filter_eq[subshopId]=deutsch ``` ### Antwort: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "items": [ { "count": 86565, "key": "Other" }, { "count": 36141, "key": "Android" }, { "count": 3675, "key": "Windows" }, { "count": 193, "key": "Linux" }, { "count": 3, "key": "Mac OS X" }, { "count": 2, "key": "iOS" } ] } ``` ### Filterfelder `subshopID`, `device` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/browser Dieser Endpunkt liefert eine Auswertung darüber, wie häufig bestimmte Browser – gruppiert nach Versionen – im angegebenen Zeitraum genutzt wurden. Die Analyse kann über die Filter `subshopId` und `device` auf bestimmte Subshops und Gerätetypen eingeschränkt werden. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/browser?from=2025-05-01T07:51:51.599Z&to=2025-05-15T07:51:51.599Z&filter_eq[subshopId]=deutsch ``` ### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 86404, "group by major-version": { "buckets": [ { "count": 86404, "key": "1" } ], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 }, "key": "Go-http-client" }, { "count": 36064, "group by major-version": { "buckets": [ { "count": 36064, "key": "2" } ], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 }, "key": "Googlebot" }, { "count": 3363, "group by major-version": { "buckets": [ { "count": 2566, "key": "136" }, { "count": 755, "key": "135" }, { "count": 17, "key": "81" }, ... ], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 }, "key": "Chrome" }, { "count": 372, "group by major-version": { "buckets": [ { "count": 332, "key": "138" }, { "count": 29, "key": "137" }, { "count": 8, "key": "120" }, { "count": 3, "key": "136" } ], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 }, "key": "Firefox" }, ... ] } ``` ### Filterfelder `subshopID`, `device` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/action Dieser Endpunkt liefert eine Übersicht darüber, wie häufig bestimmte Shop-Aktionen im angegebenen Zeitraum durchgeführt wurden. Die Auswertung kann über den Filter `subshopId` auf bestimmte Subshops eingeschränkt werden. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/action?from=2025-04-15T07:51:51.601Z&to=2025-05-15T07:51:51.601Z&filter_eq[subshopId]=deutsch ``` ### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 87563, "key": "StartpageShow" }, { "count": 37134, "key": "ProductShow" }, { "count": 3824, "key": "ViewShow" }, { "count": 1106, "key": "CategoryShow" }, { "count": 259, "key": "BasketItemAdd" }, { "count": 160, "key": "InquirySend" }, { "count": 138, "key": "SearchShow" }, { "count": 113, "key": "CheckPasswordStrength" }, { "count": 109, "key": "WatchListItemAdd" }, { "count": 106, "key": "Login" } ] } ``` ### Filterfelder `subshopID` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/importantActionsRate Dieser Endpunkt liefert Informationen darüber, in wie vielen Sitzungen wichtige Aktionen durchgeführt wurden. Dazu gehören: * Bestellung * Gutscheineinlösung * Registrierung * Adressaktualisierung * Anfragestellung * Produktzugabe zum Warenkorb Wird der Parameter `aggregation` gesetzt (`hour`, `day` oder `month`; **ohne “s”**), erfolgt die Ausgabe gruppiert nach Zeit. Zusätzlich kann über den Filter `subshopId` eine Einschränkung auf bestimmte Subshops erfolgen. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Um bei aggregierten Daten die Rate zu ermitteln, soll zuerst die Summe von `totalSessionCount.value` für jeden Subshop berechnet werden. Dann sollen die Werte `totalSessionCount.value` durch die Summe geteilt werden. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/importantActionsRate?from=2025-04-20T22:00:00.770Z&to=2025-05-20T21:59:59.770Z&aggregation=day&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=english ``` ### Antwort (aggregierte Daten) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 16, "key": 1747008000000, "key_as_string": "2025-05-12T00:00:00.000Z", "subshops": { "buckets": [ { "count": 16, "key": "deutsch", "totalSessionCount": { "value": 16 } } ], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 } }, { "count": 1, "key": 1747094400000, "key_as_string": "2025-05-13T00:00:00.000Z", "subshops": { "buckets": [ { "count": 1, "key": "deutsch", "totalSessionCount": { "value": 1 } } ], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 } }, { "count": 3, "key": 1747180800000, "key_as_string": "2025-05-14T00:00:00.000Z", "subshops": { "buckets": [ { "count": 3, "key": "deutsch", "totalSessionCount": { "value": 3 } } ], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 } }, { "count": 11, "key": 1747267200000, "key_as_string": "2025-05-15T00:00:00.000Z", "subshops": { "buckets": [ { "count": 11, "key": "deutsch", "totalSessionCount": { "value": 11 } } ], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 } } ] } ``` ### Antwort (nicht aggregierte Daten) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "totalSessionCount": 58, "convertedSessionCount": 17, "convertedSessionRatio": 0.29310344827586204 } ``` ### Filterfelder `subshopID` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/products Dieser Endpunkt liefert eine Liste der meistbesuchten Produkte im angegebenen Zeitraum, inklusive Zugriffszahlen und Produktnamen. Die Auswertung kann über den Filter `subshopId` auf bestimmte Subshops eingeschränkt werden. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/products?from=2025-05-08T22:00:00.395Z&to=2025-05-15T21:59:59.395Z&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=englisch ``` ### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 108, "key": "144-11648", "max_score": 6.618824, "name": "Flyer Option 2" }, { "count": 95, "key": "140-23474", "max_score": 6.618824, "name": "Flyer Option 1" }, { "count": 50, "key": "163-44034", "max_score": 6.618824, "name": "Kapuzenjacke" }, { "count": 16, "key": "153-83280", "max_score": 6.618824, "name": "Straight Fit Jeans" }, ... ] } ``` ### Filterfelder `subshopID` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/categories Dieser Endpunkt liefert eine Liste der meistbesuchten Kategorien im angegebenen Zeitraum, inklusive Zugriffszahlen und Kategorienamen. Die Auswertung kann über den Filter `subshopId` auf bestimmte Subshops eingeschränkt werden. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/categories?from=2025-05-14T12:00:00.167Z&to=2025-05-15T11:59:59.167Z&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=englisch ``` ### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 73, "key": "104-40827", "max_score": 6.9967184, "name": "Sale" }, { "count": 49, "key": "101-64607", "max_score": 6.9967184, "name": "Elektronik & Computer" }, { "count": 39, "key": "100-14213", "max_score": 6.9967184, "name": "Bekleidung" }, { "count": 35, "key": "102-42333", "max_score": 6.9967184, "name": "Drucksachen" }, { "count": 32, "key": "106-25201", "max_score": 6.9967184, "name": "Tiernahrung" }, { "count": 25, "key": "105-19647", "max_score": 6.9967184, "name": "Personalisierte Artikel" }, ... ] } ``` ### Filterfelder `subshopID` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/devices Dieser Endpunkt liefert eine Übersicht, wie häufig bestimmte Gerätetypen im angegebenen Zeitraum für Zugriffe auf den Shop verwendet wurden. Die Auswertung kann über den Filter `subshopId` auf bestimmte Subshops eingeschränkt werden. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/devices?from=2025-05-08T22:00:00.381Z&to=2025-05-15T21:59:59.381Z&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=englisch ``` ### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 61747, "key": "Spider" }, { "count": 1490, "key": "Other" }, { "count": 96, "key": "Nexus 5" }, { "count": 23, "key": "Nexus 5X" }, { "count": 3, "key": "Mac" }, { "count": 2, "key": "iPhone" } ] } ``` ### Filterfelder `subshopID` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/devicesList Dieser Endpunkt liefert eine Liste aller erfassten Geräte, mit denen auf den Shop zugegriffen wurde, einschließlich der jeweiligen Zugriffszahlen. Die Daten ermöglichen eine Analyse der eingesetzten Endgeräte bei Shop-Besuchen. Im Gegensatz zu [GET statistics/access/devices](#1012-get-statistics-access-devices) muss der Zeitraum nicht angegeben werden. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/devicesList ``` ### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 122513, "key": "Spider" }, { "count": 10107, "key": "Other" }, { "count": 137, "key": "Nexus 5" }, { "count": 102, "key": "Nexus 5X" }, { "count": 65, "key": "Mac" }, { "count": 11, "key": "Samsung SM-J111F" }, { "count": 10, "key": "K" }, { "count": 5, "key": "iPhone" }, { "count": 4, "key": "M2004J15SC" }, { "count": 3, "key": "Samsung SM-G930V" }, { "count": 3, "key": "Samsung SM-G965U" }, { "count": 2, "key": "Samsung SM-G965F" }, { "count": 1, "key": "Generic Feature Phone" }, { "count": 1, "key": "HTC One M9" }, { "count": 1, "key": "Huawei Crawler" }, { "count": 1, "key": "Nokia E7-00" }, { "count": 1, "key": "SM-T580" }, { "count": 1, "key": "XiaoMi Mi MIX 2S" }, { "count": 1, "key": "XiaoMi Redmi 6" }, { "count": 1, "key": "XiaoMi Redmi Note 4" } ] } ``` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/clicksCountPerSession Dieser Endpunkt liefert die durchschnittliche Anzahl an Klicks pro Besuch (Sitzung) im angegebenen Zeitraum, exakt berechnet ohne Rundung. Die Auswertung kann über den Filter `subshopId` auf einzelne Subshops eingeschränkt werden. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/clicksCountPerSession?from=2025-05-08T22:00:00.387Z&to=2025-05-15T21:59:59.387Z&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=english ``` ### Antwort ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 15.444444444444445 ``` ### Filterfelder `subshopID` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/clicksCountPerUser Dieser Endpunkt liefert die durchschnittliche Anzahl an Klicks pro Besucher im angegebenen Zeitraum. Die Auswertung kann über den Filter `subshopId` auf bestimmte Subshops eingegrenzt werden. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/clicksCountPerUser?from=2025-04-15T22:00:00.942Z&to=2025-05-15T21:59:59.942Z&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=english ``` ### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "averageClicksCount": 8 } ``` ### Filterfelder `subshopID` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/trafficPeaks Dieser Endpunkt liefert die Zeitpunkte mit den höchsten gleichzeitigen Nutzerzahlen (Spitzenverkehr) innerhalb eines definierten Zeitraums, getrennt nach Subshops. Die Aggregation erfolgt über `hours`, `days` oder `months` und ist erforderlich. Zusätzlich kann über den Filter `subshopId` gezielt auf einzelne Subshops eingeschränkt werden. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/trafficPeaks?from=2025-05-13T22:00:00.394Z&to=2025-05-20T21:59:59.394Z&aggregation=days&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=english ``` ### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "maxUsers": 2, "subshopId": "deutsch", "timestamp": "2024-10-25T17:02:34.000Z" }, { "maxUsers": 2, "subshopId": "english", "timestamp": "2024-10-25T17:02:34.000Z" }, { "maxUsers": 2, "subshopId": "deutsch", "timestamp": "2024-12-11T14:11:07.000Z" }, { "maxUsers": 0, "subshopId": "english", "timestamp": "2024-12-11T14:11:07.000Z" }, { "maxUsers": 0, "subshopId": "deutsch", "timestamp": "2025-01-30T18:35:06.000Z" }, { "maxUsers": 0, "subshopId": "english", "timestamp": "2025-01-30T18:35:06.000Z" }, { "maxUsers": 2, "subshopId": "deutsch", "timestamp": "2025-03-02T05:04:12.000Z" }, { "maxUsers": 0, "subshopId": "english", "timestamp": "2025-03-02T05:04:12.000Z" } ] } ``` ### Filterfelder `subshopID` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from`, `to` oder `aggregation` fehlen. | | 400 Bad Request | "invalidValue" | | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/sessionsWithoutRouting Dieser Endpunkt liefert die Anzahl der Sitzungen ohne weitere Navigation im Shop (Absprünge) für einen bestimmten Zeitraum, optional gruppiert nach Zeit und Subshop. Wird der Parameter `aggregation` gesetzt (`hour`, `day` oder `month`; **ohne “s”**), erfolgt die Ausgabe gruppiert nach Zeit. Zusätzlich kann über den Filter `subshopId` eine Einschränkung auf bestimmte Subshops erfolgen. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Um bei aggregierten Daten die Absprungrate auszurechnen, muss man mit GET statistics/access/totalSessionCount die Anzahl der Sitzungen für jeden Subshop holen und `filteredSessionsCount.value` durch diese Anzahl teilen. Bei nicht aggregierten Daten teilen Sie die Antwort durch die Anzahl der Sitzungen im selben Zeitraum. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/sessionsWithoutRouting?from=2025-05-08T22:00:00.226Z&to=2025-05-15T21:59:59.226Z&aggregation=day&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=englisch ``` ### Antwort (aggregierte Daten) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 0, "key": 1746662400000, "key_as_string": "2025-05-08T00:00:00.000Z", "subshops": { "buckets": [], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 } }, { "count": 225, "key": 1746748800000, "key_as_string": "2025-05-09T00:00:00.000Z", "subshops": { "buckets": [ { "count": 224, "filteredSessionsCount": { "value": 17 }, "key": "deutsch", "sessions": { "buckets": [ { "count": 1, "key": "0be4a6fc98c6f6ae5cb62ce74389970e2f6e498602ae9b311fa31661bab87cda", "logs_per_session": { "value": 1 } }, { "count": 1, "key": "0f87fa4ba5e977dfeb7e6efa1090ba0ae23cbad879920764b9ef662084aeacee", "logs_per_session": { "value": 1 } }, ... ], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 } }, { "count": 1, "filteredSessionsCount": { "value": 1 }, "key": "englisch", "sessions": { "buckets": [ { "count": 1, "key": "9812acafed4ec9b861a36d93c4ab5ecc233a4878816d28115f80c9753f60a1f3", "logs_per_session": { "value": 1 } } ], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 } } ], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 } }, { "count": 45, "key": 1746835200000, "key_as_string": "2025-05-10T00:00:00.000Z", "subshops": { "buckets": [ { "count": 45, "filteredSessionsCount": { "value": 45 }, "key": "deutsch", "sessions": { "buckets": [ { "count": 1, "key": "03d8ace9db7bcf1561085682171bde8ca5f61f31c90a86012ece5991c384f8b4", "logs_per_session": { "value": 1 } }, { "count": 1, "key": "07cba5bf5610783ef77f4a5890f8d974b081f0b4dd137ccd6a28e049d6c50dc5", "logs_per_session": { "value": 1 } }, ... ], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 } } ], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 } }, ... ] } ``` ### Antwort (nicht aggregierte Daten) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 3.0 ``` ### Filterfelder `subshopID` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/totalSessionCount Dieser Endpunkt liefert die Gesamtanzahl aller Sitzungen im angegebenen Zeitraum, optional gruppiert nach einem Aggregationsintervall. Wird der Parameter `aggregation` gesetzt (`hour`, `day` oder `month`; **ohne “s”**), erfolgt die Ausgabe gruppiert nach Zeit. Zusätzlich kann über den Filter `subshopId` eine Einschränkung auf bestimmte Subshops erfolgen. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/totalSessionCount?from=2025-05-08T22:00:00.226Z&to=2025-05-15T21:59:59.226Z&aggregation=day&filter_eq[subshopId]=englisch ``` ### Antwort (aggregierte Daten) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 3, "key": 1744761600000, "key_as_string": "2025-04-16T00:00:00.000Z", "uniqueSessions": { "value": 3 } }, { "count": 24, "key": 1744848000000, "key_as_string": "2025-04-17T00:00:00.000Z", "uniqueSessions": { "value": 8 } }, { "count": 1, "key": 1744934400000, "key_as_string": "2025-04-18T00:00:00.000Z", "uniqueSessions": { "value": 1 } }, { "count": 2, "key": 1745020800000, "key_as_string": "2025-04-19T00:00:00.000Z", "uniqueSessions": { "value": 2 } }, { "count": 1, "key": 1745107200000, "key_as_string": "2025-04-20T00:00:00.000Z", "uniqueSessions": { "value": 1 } }, { "count": 1, "key": 1745193600000, "key_as_string": "2025-04-21T00:00:00.000Z", "uniqueSessions": { "value": 1 } }, { "count": 386, "key": 1745280000000, "key_as_string": "2025-04-22T00:00:00.000Z", "uniqueSessions": { "value": 35 } }, ... ] } ``` ### Antwort (nicht aggregierte Daten) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 25544 ``` ### Filterfelder `subshopID` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/referer Dieser Endpunkt liefert eine Liste der Referrer-Domains, über die Besucher im angegebenen Zeitraum auf den Shop gelangt sind. Die Auswertung kann über den Filter `subshopId` auf einzelne Subshops eingegrenzt werden. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/referer?from=2025-05-08T22:00:00.388Z&to=2025-05-15T21:59:59.388Z&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=englisch ``` ### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 1089, "key": "test-mgoepfrich.shop.websale.net" }, { "count": 143, "key": "localhost:8000" }, { "count": 5, "key": "test-mgoepfrich-en.shop.websale.net" }, { "count": 3, "key": "test-mgoepfrich.shop.websale.net:443" }, { "count": 3, "key": "websale.atlassian.net" }, { "count": 2, "key": "185.126.240.133:80" }, { "count": 1, "key": "www.google.com" } ] } ``` ### Filterfelder `subshopID` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/countries Dieser Endpunkt liefert eine Übersicht über die Anzahl der Seitenaufrufe nach Herkunftsländern im angegebenen Zeitraum. Die Auswertung kann über den Filter `subshopId` auf bestimmte Subshops eingeschränkt werden. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/countries?from=2025-04-15T22:00:00.225Z&to=2025-05-15T21:59:59.225Z&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=englisch ``` ### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 73684, "key": "DE" }, { "count": 36390, "key": "US" }, { "count": 21731, "key": "AT" }, { "count": 125, "key": "SG" }, { "count": 22, "key": "CA" }, { "count": 20, "key": "SC" }, { "count": 19, "key": "IE" }, { "count": 17, "key": "CH" }, { "count": 11, "key": "FR" }, { "count": 7, "key": "AU" } ] } ``` ### Filterfelder `subshopID` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## GET statistics/access/lengthOfStay Dieser Endpunkt liefert die durchschnittliche Verweildauer in Sekunden für einen definierten Zeitraum, optional gruppiert nach einem übergebenen Aggregationsintervall. Der Parameter `aggregation` soll immer vorkommen. Die Aggregation erfolgt über die Werte `hours`, `days` oder `months`, bei anderen Werten gibt es keine Aggregation. Zusätzlich kann über den Filter `subshopId` die Auswertung auf bestimmte Subshops eingegrenzt werden. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. ### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/lengthOfStay?from=2024-05-31T22:00:00.168Z&to=2025-05-31T21:59:59.168Z&aggregation=months&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=english ``` ### Antwort (aggregierte Daten) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "subshopId": "deutsch", "timestamp": "2025-02-26 08:41:12", "value": 162 }, { "subshopId": "deutsch", "timestamp": "2025-03-01 16:21:41", "value": 37 }, { "subshopId": "deutsch", "timestamp": "2024-11-07 15:31:17", "value": 857 }, { "subshopId": "english", "timestamp": "2024-11-06 13:41:37", "value": 610 } ] } ``` ### Antwort (nicht aggregierte Daten) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "subshopId": "deutsch", "timestamp": "2024-11-06 13:41:37", "value": 352 } ] } ``` ### Filterfelder `subshopID` ### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | Fehlt `aggregation` oder enthält der Parameter einen ungültigen Wert, wird ohne Fehlermeldung tagesweise (`days`) aggregiert. ### GET statistics/access/allPageViews Dieser Endpunkt liefert die Gesamtanzahl aller Seitenaufrufe im angegebenen Zeitraum, optional gruppiert nach Zeitintervall und Subshop. Wird der Parameter `aggregation` übergeben (`hour`, `day` oder `month`; **ohne “s”**), werden die Daten entsprechend gruppiert zurückgegeben. Über den Filter `subshopId` kann die Auswertung auf einzelne Subshops eingegrenzt werden. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/allPageViews?from=2025-05-14T09:00:00.247Z&to=2025-05-15T08:59:59.247Z&aggregation=hour&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=englisch ``` #### Antwort (aggregierte Daten) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 2649, "key": 1746662400000, "key_as_string": "2025-05-08T00:00:00.000Z", "subshops": { "buckets": [ { "count": 1390, "key": "deutsch" }, { "count": 1259, "key": "englisch" } ], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 } }, { "count": 8209, "key": 1746748800000, "key_as_string": "2025-05-09T00:00:00.000Z", "subshops": { "buckets": [ { "count": 4383, "key": "deutsch" }, { "count": 3826, "key": "englisch" } ], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 } }, { "count": 7727, "key": 1746835200000, "key_as_string": "2025-05-10T00:00:00.000Z", "subshops": { "buckets": [ { "count": 3897, "key": "deutsch" }, { "count": 3830, "key": "englisch" } ], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 } }, ... ] } ``` #### Antwort (nicht aggregierte Daten) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} 13126 ``` #### Filterfelder `subshopID` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ### GET statistics/access/accountType Dieser Endpunkt liefert eine Auswertung der Kundentypen, die im angegebenen Zeitraum auf den Shop zugegriffen haben. Die Analyse erfolgt optional gefiltert nach einem oder mehreren Subshops. Ohne Filter werden alle Subshops berücksichtigt. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Mögliche Werte für `accountType`: `-1` → Nicht ausgewählt\ `0` → Gast\ `1` → Neukunde\ `2` → Kunde Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/accountType?from=2024-05-31T22:00:00.979Z&to=2025-05-31T21:59:59.979Z&filter_eq[subshopId]=deutsch&filter_eq[subshopId]=english ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "accountType": -1, "data": 33 }, { "accountType": 1, "data": 1 }, { "accountType": 2, "data": 15 } ] } ``` #### Filterfelder `subshopID` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ### GET statistics/access/browserList Dieser Endpunkt liefert eine Liste aller Browser, mit denen auf den Shop zugegriffen wurde, einschließlich der jeweiligen Zugriffszahlen. Die Daten dienen der Analyse der im Einsatz befindlichen Browser bei Shop-Besuchern. Im Gegensatz zu [GET statistics/access/browser](#107-get-statistics-access-browser) muss der Zeitraum nicht angegeben werden. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/browserList ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 22228, "key": "Chrome" }, { "count": 33, "key": "Firefox" }, { "count": 21, "key": "Edge" } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ### GET statistics/access/OSList Dieser Endpunkt liefert eine Übersicht aller Betriebssysteme, über die Zugriffe auf den Shop erfolgt sind, inklusive der jeweiligen Zugriffszahlen. Die Daten ermöglichen eine Auswertung der verwendeten Plattformen durch Shop-Besucher. Im Gegensatz zu [GET statistics/access/os](#get-statisticsaccessos) muss der Zeitraum nicht angegeben werden. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/OSList ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 81353, "key": "Other" }, { "count": 32327, "key": "Android" }, { "count": 9243, "key": "Windows" }, { "count": 411, "key": "Linux" }, { "count": 65, "key": "Mac OS X" }, { "count": 14, "key": "Ubuntu" }, { "count": 3, "key": "iOS" }, { "count": 1, "key": "Maemo" }, { "count": 1, "key": "Symbian^3" } ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ### GET statistics/access/actionsList Dieser Endpunkt liefert eine Liste aller im Shop erfassten Aktionen sowie deren jeweilige Häufigkeit. Die Daten geben Aufschluss darüber, wie oft bestimmte Nutzeraktionen wie Seitenaufrufe oder Checkout-Schritte erfolgt sind. Im Gegensatz zu [GET statistics/access/action](#get-statisticsaccessaction) muss der Zeitraum nicht angegeben werden. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/access/actionsList ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "count": 1043627, "key": "ViewShow" }, { "count": 663337, "key": "StartpageShow" }, { "count": 387712, "key": "CategoryShow" }, { "count": 95638, "key": "ProductShow" }, { "count": 32215, "key": "SearchShow" }, { "count": 25625, "key": "CheckoutSetFreeFields" }, { "count": 22610, "key": "CheckoutAccountTypeSelect" }, { "count": 11619, "key": "CheckoutConfirm" }, { "count": 9457, "key": "DirectOrderAdd" }, { "count": 7931, "key": "InquirySend" }, ... ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## Weitere Endpunkte ### GET statistics/newlyRegistered Dieser Endpunkt liefert die Anzahl der Neuregistrierungen im angegebenen Zeitraum, gruppiert nach einem wählbaren Aggregationsintervall. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format festgelegt. Die Aggregation erfolgt in Stunden, Tagen oder Monaten; andere Werte werden automatisch entsprechend konvertiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/newlyRegistered?from=2025-04-27T22:00:00.000Z&to=2025-05-9T14:53:01.470Z&aggregation=days ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "timestamp": "2025-04-27T22:00:00.000Z", "value": 1 }, { "timestamp": "2025-04-28T22:00:00.000Z", "value": 1 }, { "timestamp": "2025-04-29T22:00:00.000Z", "value": 4 }, { "timestamp": "2025-04-30T22:00:00.000Z", "value": 0 }, { "timestamp": "2025-05-01T22:00:00.000Z", "value": 0 }, { "timestamp": "2025-05-02T22:00:00.000Z", "value": 0 }, { "timestamp": "2025-05-03T22:00:00.000Z", "value": 0 }, { "timestamp": "2025-05-04T22:00:00.000Z", "value": 2 }, { "timestamp": "2025-05-05T22:00:00.000Z", "value": 0 }, { "timestamp": "2025-05-06T22:00:00.000Z", "value": 6 }, { "timestamp": "2025-05-07T22:00:00.000Z", "value": 0 }, { "timestamp": "2025-05-08T22:00:00.000Z", "value": 3 } ] ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from`, `to` oder `aggregation` fehlen. | | 400 Bad Request | "invalidValue" | | ### POST statistics/visitors Dieser Endpunkt liefert die täglichen Besucherzahlen der Subshops für einen frei wählbaren Zeitraum. Der Zeitraum wird über die Parameter `from` und `to` im ISO-8601-Format definiert. Für die Nutzung sind Leseberechtigungen für Statistiken erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/statistics/visitors?from=2025-04-19T22:00:00.000Z&to=2025-05-14T15:07:02.027Z ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "appUsersNumber": 0, "date": "2025-04-20T00:00:00Z", "ordersNumber": 0, "subshopId": "deutsch", "visitorsNumber": 2 }, { "appUsersNumber": 0, "date": "2025-04-21T00:00:00Z", "ordersNumber": 0, "subshopId": "deutsch", "visitorsNumber": 1 }, { "appUsersNumber": 0, "date": "2025-04-22T00:00:00Z", "ordersNumber": 0, "subshopId": "deutsch", "visitorsNumber": 18 }, { "appUsersNumber": 0, "date": "2025-04-23T00:00:00Z", "ordersNumber": 4, "subshopId": "deutsch", "visitorsNumber": 14 }, { "appUsersNumber": 0, "date": "2025-04-24T00:00:00Z", "ordersNumber": 0, "subshopId": "deutsch", "visitorsNumber": 12 }, { "appUsersNumber": 0, "date": "2025-04-25T00:00:00Z", "ordersNumber": 1, "subshopId": "deutsch", "visitorsNumber": 8 }, { "appUsersNumber": 0, "date": "2025-04-26T00:00:00Z", "ordersNumber": 0, "subshopId": "deutsch", "visitorsNumber": 15 }, { "appUsersNumber": 0, "date": "2025-04-28T00:00:00Z", "ordersNumber": 1, "subshopId": "deutsch", "visitorsNumber": 24 }, { "appUsersNumber": 0, "date": "2025-04-28T00:00:00Z", "ordersNumber": 0, "subshopId": "englisch", "visitorsNumber": 19 }, ... ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Statistiken. | | 400 Bad Request | "missing" | Die Parameter `from` oder `to` fehlen. | | 400 Bad Request | "invalidValue" | `from` oder `to` enthalten keine validen ISO 8601 Zeitwerte. | | 503 Service Unavailable | "internalError" | Statistiken konnten nicht geladen werden. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Stores Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-stores Filialen und Märkte des Shops über die Admin Interface API anlegen, abrufen, aktualisieren sowie gezielt aus dem Shopsystem entfernen. Der Endpunkt `stores/` stellt Ihnen eine Schnittstelle zur Verwaltung von Filialen (Märkten) in unserem Shop-System bereit. Mit dieser Schnittstelle können Sie Marktdaten abrufen, neue Märkte anlegen und bestehende Märkte aktualisieren. ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | --------------------------- | ------------- | --------------------- | --------------------- | --------------------- | --------------------- | | **Verwaltung der Filialen** | stores/ | | | | | ## Datenfelder eines Stores | **Name** | **Typ** | **Bedeutung** | | -------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | number | Eindeutige ID des Stores (nur lesbar). | | `info` | object | Objekt mit generellen Informationen zum Store. | | `info.name` | string | Name des Stores. | | `info.street` | string | Straße und Hausnummer des Stores. | | `info.zipCode` | string | Postleitzahl des Stores. | | `info.city` | string | Stadt des Stores. | | `info.country` | string | Ländercode des Stores (z.B. `DE`). | | `info.zipcodes` | array | Liste von Postleitzahl-Präfixen, die dem Store zugeordnet sind. | | `info.zipcodes[].prefix` | string | Postleitzahl-Präfix. | | `info.zipcodes[].country` | string | Ländercode des Postleitzahl-Präfixes. | | `info.timeZone` | string | Zeitzone des Stores (z.B. `Europe/Berlin`). | | `info.metadata` | object | Beliebige Zusatzinformationen des Stores | | `storageId` | string | Lager-ID des Stores (wird für die Funktion “Abholung im Markt” verwendet). | | `subshops` | array | Liste der Subshops, für die dieser Store freigeschaltet ist. | | `location` | object | Geografische Koordinaten des Stores. | | `location.longitude` | number | Längengrad des Stores. | | `location.latitude` | number | Breitengrad des Stores. | | `openingHours` | object | Öffnungszeiten des Stores. | | `openingHours.{0-6}` | array | Reguläre Öffnungszeiten je Wochentag (0=Sonntag, 6=Samstag). Jeder Eintrag ist ein Array von Zeitfenstern. Ein leeres Array bedeutet “geschlossen”. | | `openingHours.{0-6}[].startTime` | number | Öffnungszeit in Sekunden seit Tagesbeginn (z.B. 08:00 Uhr = `28800`). | | `openingHours.{0-6}[].endTime` | number | Schließzeit in Sekunden seit Tagesbeginn (z.B. 18:00 Uhr = `64800`). Muss größer als `startTime` sein. | | `openingHours.specialDays` | object | Sonderöffnungszeiten. Der Key hat das Format `-` (z.B. `12-24`). Jeder Wert ist ein Array von Zeitfenstern (wie bei den Wochentagen). | | `clickAndCollect` | boolean | Gibt an, ob der Markt für Click & Collect freigeschaltet ist. | | `createdAt` | string | Erstellungszeitpunkt (ISO 8601-Format, UTC, nur lesbar). | | `updatedAt` | string | Letzter Aktualisierungszeitpunkt (ISO 8601-Format, UTC, nur lesbar). | #### Beispiel des Datensatzes ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": 42, "info": { "name": "Markt Musterstadt", "street": "Musterstra\u00dfe 1", "zipCode": "12345", "city": "Musterstadt", "country": "DE", "zipcodes": [ { "prefix": "123", "country": "DE" }, { "prefix": "124", "country": "DE" } ], "timeZone": "Europe/Berlin", "metadata": {} }, "storageId": "storage-99", "subshops": ["deutsch", "english"], "location": { "longitude": 13.405, "latitude": 52.52 }, "openingHours": { "0": [], "1": [{ "startTime": 28800, "endTime": 64800 }], "2": [{ "startTime": 28800, "endTime": 64800 }], "3": [{ "startTime": 28800, "endTime": 64800 }], "4": [{ "startTime": 28800, "endTime": 64800 }], "5": [{ "startTime": 28800, "endTime": 72000 }], "6": [{ "startTime": 36000, "endTime": 57600 }], "specialDays": { "12-24": [{ "startTime": 28800, "endTime": 43200 }], "12-25": [] } }, "clickAndCollect": true, "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-06-20T14:45:00.000Z" } ``` ## Verwendung der Methoden ### GET stores Diese Methode liefert eine Liste aller Märkte aus dem Admin-Interface des Shops. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/stores/ ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "id": 42, "info": { "name": "Markt Musterstadt", "street": "Musterstra\u00dfe 1", "zipCode": "12345", "city": "Musterstadt", "country": "DE", "zipcodes": [ { "prefix": "123", "country": "DE" } ], "timeZone": "Europe/Berlin", "metadata": {} }, "storageId": "storage-99", "subshops": ["deutsch"], "location": { "longitude": 13.405, "latitude": 52.52 }, "openingHours": { "0": [], "1": [{ "startTime": 28800, "endTime": 64800 }], "2": [{ "startTime": 28800, "endTime": 64800 }], "3": [{ "startTime": 28800, "endTime": 64800 }], "4": [{ "startTime": 28800, "endTime": 64800 }], "5": [{ "startTime": 28800, "endTime": 72000 }], "6": [{ "startTime": 36000, "endTime": 57600 }], "specialDays": {} }, "clickAndCollect": true, "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-06-20T14:45:00.000Z" } ], "nextPageToken": "Mw", "totalCount": 1 } ``` #### Filterfelder `id`, `subshops`, `clickAndCollect`, `storageId`, `createdAt`, `updatedAt` #### Sortierfelder `id`, `clickAndCollect`, `storageId`, `createdAt`, `updatedAt` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Store-Daten. | | 400 Bad Request | "invalidValue" | `size` ∉ \[1;300]
    `pageToken` ist keine Zahl oder kleiner als 0. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET stores/\{id} Diese Methode ruft die Details eines einzelnen Stores anhand seiner eindeutigen Store-ID ab. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/stores/42 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": 42, "info": { "name": "Markt Musterstadt", "street": "Musterstra\u00dfe 1", "zipCode": "12345", "city": "Musterstadt", "country": "DE", "zipcodes": [ { "prefix": "123", "country": "DE" }, { "prefix": "124", "country": "DE" } ], "timeZone": "Europe/Berlin", "metadata": {} }, "storageId": "storage-99", "subshops": ["deutsch"], "location": { "longitude": 13.405, "latitude": 52.52 }, "openingHours": { "0": [], "1": [{ "startTime": 28800, "endTime": 64800 }], "2": [{ "startTime": 28800, "endTime": 64800 }], "3": [{ "startTime": 28800, "endTime": 64800 }], "4": [{ "startTime": 28800, "endTime": 64800 }], "5": [{ "startTime": 28800, "endTime": 72000 }], "6": [{ "startTime": 36000, "endTime": 57600 }], "specialDays": { "12-24": [{ "startTime": 28800, "endTime": 43200 }] } }, "clickAndCollect": true, "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-06-20T14:45:00.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ---------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Store-Daten. | | 400 Bad Request | "invalidValue" | Die Store-ID ist ungültig (keine gültige Zahl). | | 404 Not Found | | Der Store mit der angegebenen ID wurde nicht gefunden. | ### POST stores Diese Methode erstellt einen neuen Store. Alle Felder außer `id`, `createdAt` und `updatedAt` sind bei der Erstellung erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/stores ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "info": { "name": "Neuer Markt", "street": "Beispielstra\u00dfe 5", "zipCode": "54321", "city": "Beispielstadt", "country": "DE", "zipcodes": [ { "prefix": "543", "country": "DE" } ], "timeZone": "Europe/Berlin", "metadata": {} }, "storageId": "storage-10", "subshops": ["deutsch"], "location": { "longitude": 9.993, "latitude": 53.551 }, "openingHours": { "0": [], "1": [{ "startTime": 28800, "endTime": 64800 }], "2": [{ "startTime": 28800, "endTime": 64800 }], "3": [{ "startTime": 28800, "endTime": 64800 }], "4": [{ "startTime": 28800, "endTime": 64800 }], "5": [{ "startTime": 28800, "endTime": 64800 }], "6": [{ "startTime": 36000, "endTime": 43200 }], "specialDays": {} }, "clickAndCollect": false } ``` #### Antwort Die Antwort enthält das vollständige Store-Objekt mit der zugewiesenen `id` sowie den Feldern `createdAt` und `updatedAt`. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": 43, "info": { "name": "Neuer Markt", "street": "Beispielstra\u00dfe 5", "zipCode": "54321", "city": "Beispielstadt", "country": "DE", "zipcodes": [ { "prefix": "543", "country": "DE" } ], "timeZone": "Europe/Berlin", "metadata": {} }, "storageId": "storage-10", "subshops": ["deutsch"], "location": { "longitude": 9.993, "latitude": 53.551 }, "openingHours": { "0": [], "1": [{ "startTime": 28800, "endTime": 64800 }], "2": [{ "startTime": 28800, "endTime": 64800 }], "3": [{ "startTime": 28800, "endTime": 64800 }], "4": [{ "startTime": 28800, "endTime": 64800 }], "5": [{ "startTime": 28800, "endTime": 64800 }], "6": [{ "startTime": 36000, "endTime": 43200 }], "specialDays": {} }, "clickAndCollect": false, "createdAt": "2025-06-20T14:45:00.000Z", "updatedAt": "2025-06-20T14:45:00.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Store-Daten. | | 400 Bad Request | "badRequest" | Der Request-Body ist kein gültiges JSON-Objekt. | | 400 Bad Request | "missing" | Ein erforderliches Feld fehlt im Request-Body. Das betroffene Feld wird im `errorContext` angegeben. | | 400 Bad Request | "invalidFormat" | Ein Feld hat einen falschen Datentyp. Der erwartete Typ wird im `errorContext` unter `expectedType` angegeben. | | 400 Bad Request | "invalidValue" | Ein Feldwert ist ungültig (z.B. ungültige Zeitzone, `startTime` ≥ `endTime`, ungültiges Datumsformat bei `specialDays`). | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request-Body gesendet. | ### PUT stores/\{id} Diese Methode aktualisiert einen bestehenden Store anhand seiner eindeutigen Store-ID. Es können einzelne oder mehrere Felder übergeben werden – nur die gesendeten Felder werden aktualisiert. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/stores/42 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "clickAndCollect": true, "storageId": "storage-77", "openingHours": { "6": [{ "startTime": 36000, "endTime": 50400 }], "specialDays": { "12-31": [{ "startTime": 28800, "endTime": 36000 }] } } } ``` #### Antwort Die Antwort enthält das vollständige aktualisierte Store-Objekt. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": 42, "info": { "name": "Markt Musterstadt", "street": "Musterstra\u00dfe 1", "zipCode": "12345", "city": "Musterstadt", "country": "DE", "zipcodes": [ { "prefix": "123", "country": "DE" }, { "prefix": "124", "country": "DE" } ], "timeZone": "Europe/Berlin", "metadata": {} }, "storageId": "storage-77", "subshops": ["deutsch", "english"], "location": { "longitude": 13.405, "latitude": 52.52 }, "openingHours": { "0": [], "1": [{ "startTime": 28800, "endTime": 64800 }], "2": [{ "startTime": 28800, "endTime": 64800 }], "3": [{ "startTime": 28800, "endTime": 64800 }], "4": [{ "startTime": 28800, "endTime": 64800 }], "5": [{ "startTime": 28800, "endTime": 72000 }], "6": [{ "startTime": 36000, "endTime": 50400 }], "specialDays": { "12-24": [{ "startTime": 28800, "endTime": 43200 }], "12-31": [{ "startTime": 28800, "endTime": 36000 }] } }, "clickAndCollect": true, "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-06-20T15:00:00.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Aktualisieren von Store-Daten. | | 400 Bad Request | "invalidValue" | Die Store-ID ist ungültig (keine gültige Zahl). | | 404 Not Found | | Der Store mit der angegebenen ID wurde nicht gefunden. | | 400 Bad Request | "badRequest" | Der Request-Body ist kein gültiges JSON-Objekt. | | 400 Bad Request | "missing" | Ein Pflichtunterfeld fehlt in einem Array-Element. Betroffen: `startTime` oder `endTime` in Zeitfenstern, `prefix` oder `country` in Postleitzahl-Einträgen. | | 400 Bad Request | "invalidFormat" | Ein Feld hat einen falschen Datentyp. Der erwartete Typ wird im `errorContext` unter `expectedType` angegeben. | | 400 Bad Request | "invalidValue" | Ein Feldwert ist ungültig (z.B. ungültige Zeitzone, `startTime` ≥ `endTime`, ungültiges Datumsformat bei `specialDays`). | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request-Body gesendet. | ### DELETE stores/\{id} Diese Methode löscht einen bestehenden Store anhand seiner eindeutigen Store-ID. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/stores/42 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Stores. | | 400 Bad Request | "invalidValue" | `id` ist ungültig. | | 404 Not Found | | Store mit `id`=`{id}` wurde nicht gefunden. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Stripe-Onboarding Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-stripe-onboarding Verbundene Stripe-Konten über die Admin Interface API anlegen, einsehen, aktualisieren, löschen und Onboarding-Links für Shops erzeugen. Der Endpunkt `payment/stripeonboarding` bietet eine Schnittstelle zur Verwaltung von verbundenen Stripe-Konten für Shops. Sie ermöglicht das Erstellen, Einsehen, Aktualisieren und Löschen dieser Konten. Zusätzlich generiert die API Onboarding-Links mit Rücksprung- und Refresh-URLs. Zugriffe sind durch feingranulare Berechtigungen (Lesen/Schreiben/Erstellen/Löschen) geschützt; Antworten erfolgen als JSON. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | --------------- | ------------------------ | --------------------- | --------------------- | --------------------- | --------------------- | | **Anfragen** | payment/stripeonboarding | | | | | ## Stripe-Onboarding-Vorgang Globale Parameter wie der Betriebsmodus sind in der Konfiguration `payment.stripe` hinterlegt. #### Datenfelder eines Eintrags | **Name** | **Typ** | **Verwendung** | | -------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **id** | Integer | Interner Primärschlüssel des Onboarding-Eintrags. | | **accountId** | String | Stripe Connected Account-ID (z. B. `acct_1S6Qs6P7aiy99C1h`). | | **status** | Integer | Aktueller Onboarding-Status, abgeleitet u. a. aus E-Mail-Bestätigung, Zahlungsfähigkeit und Antwortvalidität.
    Mögliche Werte:
    `0` = MissingData (fehlende Pflichtangaben im Onboarding)
    `1` = MissingTos (Nutzungsbedingungen nicht akzeptiert)
    `2` = ChargesDisabled (Zahlungsannahme deaktiviert)
    `3` = PayoutDisabled (Auszahlungen deaktiviert)
    `4` = PayoutEnabled (Zahlungen & Auszahlungen aktiviert) | | **mode** | Integer | Betriebsmodus des Eintrags (aus Konfiguration ermittelt): Produktion oder Test.
    Mögliche Werte:
    `0` = Sandbox
    `1` = Live | | **email** | String | E-Mail-Adresse des Stripe-Kontos. | | **tosAccepted** | Boolean | Gibt an, ob die Stripe-Nutzungsbedingungen akzeptiert wurden. | | **detailsSubmitted** | Boolean | Gibt an, ob das Onboarding-Formular bei Stripe „übermittelt“ wurde (`details_submitted`). | | **chargesEnabled** | Boolean | Gibt an, ob Zahlungen erstellt/erfasst werden dürfen. | | **payoutsEnabled** | Boolean | Gibt an, ob Auszahlungen auf das Bankkonto freigeschaltet sind. | | **capabilities** | Objekt | Spiegel der Stripe-Capabilities (z. B. `card_payments`, `transfers`) mit Status (`active/pending/inactive`). Detaillierte Kompetenzmatrix des Kontos. | | **paymentMethods** | Array | Freigegebene Zahlungsarten. | | **businessType** | String | Typ des Unternehmens laut Stripe (`individual`, `company`, `non_profit`, …). Kann leer sein, wenn noch nicht gesetzt. | | **createdAt** | String | Zeitpunkt der Erstellung (ISO 8601-Format, UTC). | | **updatedAt** | String | Zeit der letzten Aktualisierung des Eintrags (ISO 8601-Format, UTC). | | **deletedAt** | String | Zeitpunkt der Löschung (ISO 8601-Format, UTC). **Hinweis:** Der Standardwert `1970-01-01T00:00:00.000Z` signalisiert „nicht gelöscht“. | | **rawResponse** | Objekt | Vollständige, ungefilterte Antwort der Stripe-Account-API (als JSON-Objekt) zur Nachverfolgung/Debugging. | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountId": "acct_1S6Qs6P7aiy99C1h", "businessType": "", "capabilities": {}, "chargesEnabled": false, "createdAt": "2025-09-12T06:54:17.000Z", "deletedAt": "1970-01-01T00:00:00.000Z", "detailsSubmitted": false, "email": "", "id": 1, "mode": 0, "paymentMethods": [ { "available": false, "type": "alipay" }, { "available": true, "type": "amazon_pay" }, { "available": true, "type": "apple_pay" }, ... ], "payoutsEnabled": false, "rawResponse": { ... }, "status": 0, "tosAccepted": true, "updatedAt": "2025-09-12T06:54:17.000Z" } ``` #### Beispiel von rawResponse ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "business_profile": { "annual_revenue": null, "estimated_worker_count": null, "mcc": null, "minority_owned_business_designation": null, "name": null, "support_address": null, "support_email": null, "support_phone": null, "support_url": null, "url": null }, "business_type": null, "capabilities": {}, "charges_enabled": false, "controller": { "fees": { "payer": "account" }, "is_controller": true, "losses": { "payments": "stripe" }, "requirement_collection": "stripe", "stripe_dashboard": { "type": "full" }, "type": "application" }, "country": "DE", "created": 1757660056, "default_currency": "eur", "details_submitted": false, "email": null, "external_accounts": { "data": [], "has_more": false, "object": "list", "total_count": 0, "url": "/v1/accounts/acct_1S6Qs6P7aiy99C1h/external_accounts" }, "future_requirements": { "alternatives": [], "current_deadline": null, "currently_due": [], "disabled_reason": null, "errors": [], "eventually_due": [], "past_due": [], "pending_verification": [] }, "id": "acct_1S6Qs6P7aiy99C1h", "metadata": {}, "object": "account", "payouts_enabled": false, "requirements": { "alternatives": [], "current_deadline": null, "currently_due": [ "business_profile.product_description", "business_profile.support_phone", "business_profile.url", "external_account", "tos_acceptance.date", "tos_acceptance.ip" ], "disabled_reason": "requirements.past_due", "errors": [], "eventually_due": [ "business_profile.product_description", "business_profile.support_phone", "business_profile.url", "external_account", "tos_acceptance.date", "tos_acceptance.ip" ], "past_due": [ "business_profile.product_description", "business_profile.support_phone", "business_profile.url", "external_account", "tos_acceptance.date", "tos_acceptance.ip" ], "pending_verification": [] }, "settings": { "bacs_debit_payments": { "display_name": null, "service_user_number": null }, "branding": { "icon": null, "logo": null, "primary_color": null, "secondary_color": null }, "card_issuing": { "tos_acceptance": { "date": null, "ip": null } }, "card_payments": { "decline_on": { "avs_failure": false, "cvc_failure": false }, "statement_descriptor_prefix": null, "statement_descriptor_prefix_kana": null, "statement_descriptor_prefix_kanji": null }, "dashboard": { "display_name": null, "timezone": "Etc/UTC" }, "invoices": { "default_account_tax_ids": null, "hosted_payment_method_save": "offer" }, "payments": { "statement_descriptor": null, "statement_descriptor_kana": null, "statement_descriptor_kanji": null }, "payouts": { "debit_negative_balances": true, "schedule": { "delay_days": 7, "interval": "daily" }, "statement_descriptor": null }, "sepa_debit_payments": {} }, "tos_acceptance": { "date": null }, "type": "standard" } ``` ## Methoden für Stripe-Onboarding Dieser Abschnitt beschreibt die Endpunkte zur Verwaltung einzelner Stripe-Onboarding-Einträge. ### GET payment/stripeonboarding Mit diesem Endpunkt kann eine Liste der vorhandenen Onboarding-Einträge des aktuellen Shops geladen werden. Dabei werden Such- und Filterparameter aus der Anfrage berücksichtigt und auf `deleted=false` begrenzt. Für die Nutzung sind Leseberechtigungen für Stripe-Onboarding-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/payment/stripeonboarding?size=100 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "accountId": "acct_1S6Qs6P7aiy99C1h", "businessType": "", "capabilities": {}, "chargesEnabled": false, "createdAt": "2025-09-12T06:54:17.000Z", "deletedAt": "1970-01-01T00:00:00.000Z", "detailsSubmitted": false, "email": "", "id": 1, "mode": 0, "paymentMethods": [], "payoutsEnabled": false, "rawResponse": {}, "status": 0, "tosAccepted": false, "updatedAt": "2025-09-12T06:54:17.000Z" }, { "accountId": "acct_1S6Qs70EemSb0vRy", "businessType": "", "capabilities": {}, "chargesEnabled": false, "createdAt": "2025-09-12T06:54:18.000Z", "deletedAt": "1970-01-01T00:00:00.000Z", "detailsSubmitted": false, "email": "", "id": 2, "mode": 0, "paymentMethods": [], "payoutsEnabled": false, "rawResponse": {}, "status": 0, "tosAccepted": false, "updatedAt": "2025-09-12T06:54:18.000Z" }, ... ], "nextPageToken": "Mw", "totalCount": 4 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Stripe-Onboarding-Daten. | | 400 Bad Request | "invalidValue" | `sort`-Richtung ist ungültig (nicht "asc" oder "desc").
    `size` ∉ \[1;300]
    `pageToken` ist keine Zahl oder kleiner als 0. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET payment/stripeonboarding/\{id} Mit diesem Endpunkt kann ein einzelner Onboarding-Eintrag anhand seiner ID geladen werden. Für die Nutzung dieses Endpunkts sind Leseberechtigungen für Stripe-Onboarding-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/payment/stripeonboarding/1 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountId": "acct_1S6Qs6P7aiy99C1h", "businessType": "", "capabilities": {}, "chargesEnabled": false, "createdAt": "2025-09-12T06:54:17.000Z", "deletedAt": "1970-01-01T00:00:00.000Z", "detailsSubmitted": false, "email": "", "id": 1, "mode": 0, "paymentMethods": [], "payoutsEnabled": false, "rawResponse": {}, "status": 0, "tosAccepted": false, "updatedAt": "2025-09-12T06:54:17.000Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ---------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Stripe-Onboarding-Daten. | | 404 Not Found | | Die Daten wurden nicht gefunden. | ### POST payment/stripeonboarding Mit diesem Endpunkt wird ein verbundenes Stripe-Konto erstellt und dazu ein lokaler Onboarding-Eintrag im Modus Live oder Sandbox angelegt. Als Ergebnis wird ein Onboarding-Link (URL) zurückgegeben, über den die Einrichtung bei Stripe abgeschlossen werden kann. Für die Nutzung dieses Endpunkts sind Erstellberechtigungen für Stripe-Onboarding-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/payment/stripeonboarding ``` #### Request Body ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "url": "https://connect.stripe.com/setup/s/acct_1S7cvB14358LTRqf/0LSOodpShtzK" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------- | ----------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Stripe-Onboarding-Daten. | | 503 Service Unavailable | "serviceUnavailable" | Es konnte kein Stripe-Konto angelegt werden.
    Der Onboarding-Link konnte nicht erstellt werden. | | 503 Service Unavailable | "internalError" | Das Speichern von Daten in der WEBSALE-Datenbank ist fehlgeschlagen. | ### PUT payment/stripeonboarding/\{id} Dieser Endpunkt aktualisiert einen bestehenden Onboarding-Eintrag anhand seiner ID und unterscheidet zwei sinnvolle Anwendungsfälle über das Feld `type` im Request-Body:\ – `type = "finish"`: Der Eintrag wird mit dem aktuellen Zustand des verbundenen Stripe-Kontos synchronisiert. Dabei werden u. a. übermittelte Stammdaten, ToS-Annahme, Freigabe von Zahlungen und Auszahlungen geprüft und in einen verständlichen Status überführt (z. B. „fehlende Daten“, „ToS nicht bestätigt“, „Zahlungen/Auszahlungen deaktiviert“ oder „Auszahlungen aktiviert“). Zusätzlich werden E-Mail, Capabilities, die Standard-Konfiguration der Zahlungsarten und die unveränderte Rohantwort gespeichert. Das Ergebnis ist der aktualisierte Eintrag als JSON.\ – `type = "refresh"`: Es wird ein neuer Onboarding-Link erzeugt, damit der Händler die Einrichtung bei Stripe nahtlos fortsetzen kann (z. B. nach einer Unterbrechung oder wenn weitere Angaben nötig sind). Für die Nutzung dieses Endpunkts sind Schreibberechtigungen für Stripe-Onboarding-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/payment/stripeonboarding/2 ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "type": "finish" } ``` #### Antwort, wenn `type` gleich `"finish"` gilt ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountId": "acct_1S7cvB14358LTRqf", "businessType": "", "capabilities": {}, "chargesEnabled": false, "createdAt": "2025-09-15T13:58:24.000Z", "deletedAt": "1970-01-01T00:00:00.000Z", "detailsSubmitted": false, "email": "", "id": 2, "mode": 0, "paymentMethods": [ { "available": false, "type": "alipay" }, { "available": false, "type": "amazon_pay" }, { "available": true, "type": "apple_pay" }, { "available": false, "type": "bancontact" }, { "available": false, "type": "billie" }, { "available": false, "type": "blik" }, { "available": true, "type": "card" }, { "available": false, "type": "cartes_bancaires" }, { "available": false, "type": "customer_balance" }, { "available": false, "type": "eps" }, { "available": false, "type": "giropay" }, { "available": false, "type": "google_pay" }, ... ], "payoutsEnabled": false, "rawResponse": { "business_profile": { "annual_revenue": null, "estimated_worker_count": null, "mcc": null, "minority_owned_business_designation": null, "name": null, "support_address": null, "support_email": null, "support_phone": null, "support_url": null, "url": null }, "business_type": null, "capabilities": {}, "charges_enabled": false, "controller": { "fees": { "payer": "account" }, "is_controller": true, "losses": { "payments": "stripe" }, "requirement_collection": "stripe", "stripe_dashboard": { "type": "full" }, "type": "application" }, "country": "DE", "created": 1757944702, "default_currency": "eur", "details_submitted": false, "email": null, "external_accounts": { "data": [], "has_more": false, "object": "list", "total_count": 0, "url": "/v1/accounts/acct_1S7cvB14358LTRqf/external_accounts" }, "future_requirements": { "alternatives": [], "current_deadline": null, "currently_due": [], "disabled_reason": null, "errors": [], "eventually_due": [], "past_due": [], "pending_verification": [] }, "id": "acct_1S7cvB14358LTRqf", "metadata": {}, "object": "account", "payouts_enabled": false, "requirements": { "alternatives": [], "current_deadline": null, "currently_due": [ "business_profile.product_description", "business_profile.support_phone", "business_profile.url", "external_account", "tos_acceptance.date", "tos_acceptance.ip" ], "disabled_reason": "requirements.past_due", "errors": [], "eventually_due": [ "business_profile.product_description", "business_profile.support_phone", "business_profile.url", "external_account", "tos_acceptance.date", "tos_acceptance.ip" ], "past_due": [ "business_profile.product_description", "business_profile.support_phone", "business_profile.url", "external_account", "tos_acceptance.date", "tos_acceptance.ip" ], "pending_verification": [] }, "settings": { "bacs_debit_payments": { "display_name": null, "service_user_number": null }, "branding": { "icon": null, "logo": null, "primary_color": null, "secondary_color": null }, "card_issuing": { "tos_acceptance": { "date": null, "ip": null } }, "card_payments": { "decline_on": { "avs_failure": false, "cvc_failure": false }, "statement_descriptor_prefix": null, "statement_descriptor_prefix_kana": null, "statement_descriptor_prefix_kanji": null }, "dashboard": { "display_name": null, "timezone": "Etc/UTC" }, "invoices": { "default_account_tax_ids": null, "hosted_payment_method_save": "offer" }, "payments": { "statement_descriptor": null, "statement_descriptor_kana": null, "statement_descriptor_kanji": null }, "payouts": { "debit_negative_balances": true, "schedule": { "delay_days": 7, "interval": "daily" }, "statement_descriptor": null }, "sepa_debit_payments": {} }, "tos_acceptance": { "date": null }, "type": "standard" }, "status": 0, "tosAccepted": true, "updatedAt": "2025-09-15T13:58:24.000Z" } ``` #### Antwort, wenn `type` gleich `"refresh"` gilt ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "url": "https://connect.stripe.com/setup/s/acct_1S7dWp1yCkcDDzUj/biADCkORd6Jm" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Stripe-Onboarding-Daten. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | | | 404 Not Found | | `id` fehlt oder ist keine Ganzzahl.
    Der Eintrag wurde in der WEBSALE-Datenbank nicht gefunden.
    Das Aktualisieren von Daten ist fehlgeschlagen. | | 503 Service Unavailable | "serviceUnavailable" | Das Stripe-Konto konnte nicht geladen werden.
    Der Onboarding-Link konnte nicht erstellt werden. | ### DELETE payment/stripeonboarding/\{id} Mit diesem Endpunkt kann ein bestehender Onboarding-Eintrag anhand seiner ID entfernt werden. Das Konto bei Stripe bleibt bestehen, aber der aktuelle Shop wird keine Zahlungen mehr für dieses Konto verarbeiten. Für die Nutzung dieses Endpunkts sind Löschberechtigungen für Stripe-Onboarding-Daten erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/payment/stripeonboarding/3 ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ------------------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Stripe-Onboarding-Daten. | | 404 Not Found | | Es wurde kein Eintrag gefunden, oder das Löschen ist fehlgeschlagen. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Template-Optionen Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-template-optionen Template-Optionen über die Admin Interface API verwalten: definierte Optionen auflisten, deren Einstellungen sowie Werte lesen und schreiben. Der Endpunkt `templates/options` stellt eine Schnittstelle zur Verwaltung der Template-Optionen bereit. Über diese Schnittstelle lassen sich alle im Template definierten Optionen auflisten, ihre Einstellungen abrufen und bearbeiten sowie die gepflegten Werte einzelner Optionen lesen und speichern. Optionen werden im Template definiert und anschließend im Admin-Interface bzw. über diese API gepflegt. Die Definition selbst (Name, Typ und Einschränkungen) ist durch das Template fest vorgegeben und kann über die API nicht verändert werden. Wie Optionen im Template definiert und ausgelesen werden, ist im Dokument [Optionen](/frontend/referenz/optionen) beschrieben. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | --------------------- | ------------------ | --------------------- | ------------------- | --------------------- | ------------------- | | **Template-Optionen** | templates/options/ | | | | | ## Datenfelder | **Name** | **Typ** | **Bedeutung** | | ------------------ | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | **name** | String | Eindeutiger Name der Option, wie er im Template definiert wurde. | | **type** | String | Typ der Option (`String`, `Int`, `Float`, `Bool` oder `Enum`). Bestimmt die Eingabemaske im Admin-Interface. | | **constraints** | Objekt | Typabhängige Einschränkungen der Option, z. B. `values` bei Typ `Enum` oder `min`/`max` bei `Int` und `Float`. | | **attachTo** | String | Konfigurationstyp, an den die Option gebunden ist (z. B. `payment.payment`). Ist das Feld leer, handelt es sich um eine globale Option. | | **displayOptions** | Objekt \| null | Steuert über `location` die Anzeigeposition der Option in der Konfigurationsoberfläche. `null`, wenn keine Position festgelegt wurde. | | **label** | String | Anzeigelabel der Option. Dient ausschließlich der Anzeige und kann bearbeitet werden. | | **description** | String | Beschreibung der Option. Dient ausschließlich der Anzeige und kann bearbeitet werden. | | **subshopIds** | Array von Strings | Liste der Subshops, in denen die Option definiert ist (z. B. `["deutsch"]`). | | **defaultValue** | beliebig \| null | Admin-konfigurierter Default-Wert der Option (Typ entspricht `type`). `null`, wenn kein eigener Default gesetzt ist und der Typ-Standard verwendet wird. | ## Methoden für Template-Optionen Die folgenden Methoden ermöglichen es, die definierten Optionen aufzulisten, ihre Einstellungen zu lesen und zu bearbeiten sowie die gepflegten Werte einzelner Optionen abzurufen und zu speichern. Die Nutzung setzt entsprechende Lese- bzw. Schreibrechte für Template-Daten voraus. ### GET templates/options Mit dieser Methode wird eine Liste aller im Template definierten Optionen zurückgegeben. Jeder Eintrag enthält die Definition der jeweiligen Option (u. a. `name`, `type`, `constraints` und `attachTo`) sowie das bearbeitbare `label` und die `description`. Der Endpunkt funktioniert wie alle anderen suchbaren API-Endpunkte und unterstützt Filterung, Sortierung und Paginierung. Leseberechtigungen für Template-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/templates/options ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "attachTo": "", "constraints": { "values": [ "grid", "list", "slider" ] }, "description": "", "displayOptions": null, "label": "", "name": "enumValue", "subshopIds": [ "deutsch" ], "type": "Enum" }, ... ], "nextPageToken": "MA", "totalCount": 5 } ``` #### Filterfelder `name`, `type`, `attachTo`, `subshopId` #### Sortierfelder `name`, `type` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | ------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Template-Daten. | | 400 Bad Request | "invalidValue" | `size` ∉ \[1;300]
    `pageToken` ist keine Zahl oder kleiner als 0. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET templates/options/\{name} Mit dieser Methode werden die Einstellungen einer einzelnen Option anhand ihres Namens zurückgegeben. Leseberechtigungen für Template-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/templates/options/enumValue ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "attachTo": "", "constraints": { "values": [...] }, "description": "", "displayOptions": null, "label": "", "name": "enumValue", "subshopIds": [ "deutsch" ], "type": "Enum" } ``` Das Feld `constraints.values` ist nur bei Optionen vom Typ `Enum` enthalten. #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Template-Daten. | | 404 Not Found | | Die Option wurde nicht gefunden. | ### PUT templates/options/\{name} Mit dieser Methode werden die Einstellungen einer Option aktualisiert. Geändert werden können `label` und `description`. Optional kann zusätzlich `defaultValue` gesetzt werden, der admin-konfigurierte Default-Wert der Option (muss zum Options-Typ passen). Ein `null`-Wert setzt den Default auf den systemseitigen Typ-Standard zurück. Nur `label`, `description` und `defaultValue` sind änderbar, `name`, `type`, `constraints` und `attachTo` sind durch die Definition im Template fest vorgegeben und lassen sich über die API nicht ändern. Für diesen Endpunkt ist die Berechtigung `Publish` (Veröffentlichen von Template-Daten) erforderlich. Eine separate Schreibberechtigung existiert für Template-Optionen nicht. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/templates/options/enumValue ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "", "description": "" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "attachTo": "", "constraints": { "values": [...] }, "description": "", "displayOptions": null, "label": "", "name": "enumValue", "subshopIds": [ "deutsch" ], "type": "Enum" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ----------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Template-Daten. | | 400 Bad Request | | Request-Body konnte nicht als JSON geladen werden. | | 404 Not Found | | Die Option wurde nicht gefunden. | ### GET templates/options/\{name}/value/\{nodeId} Mit dieser Methode wird der gepflegte Wert einer Option zurückgegeben. Der Parameter `{nodeId}` wird nur benötigt, wenn bei der Definition der Option `attachTo` angegeben wurde. Bei globalen Optionen (ohne `attachTo`) entfällt er. Da der Wert pro Subshop gepflegt wird, sollte die URL den Parameter `subshopId` enthalten. Wird er nicht angegeben, wird der erste Subshop des Shops verwendet. Leseberechtigungen für Template-Daten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/templates/options/footerShowPaymentIcon/value/payment.payment.ApplePay?subshopId=deutsch ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "footerShowPaymentIcon", "nodeId": "payment.payment.ApplePay", "value": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Template-Daten. | | 404 Not Found | | Die Option `{name}` wurde nicht gefunden. Ist zur Option zwar kein Wert gepflegt, antwortet der Endpunkt mit HTTP 200 und dem Default-Wert der Option, nicht mit 404. | ### PUT templates/options/\{name}/value/\{nodeId} Mit dieser Methode wird der Wert einer Option gespeichert. Der Parameter `{nodeId}` wird nur benötigt, wenn bei der Definition der Option `attachTo` angegeben wurde. Bei globalen Optionen (ohne `attachTo`) entfällt er. Da der Wert pro Subshop gepflegt wird, sollte die URL den Parameter `subshopId` enthalten. Wird er nicht angegeben, wird der erste Subshop des Shops verwendet. Für diesen Endpunkt ist die Berechtigung `Publish` (Veröffentlichen von Template-Daten) erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/templates/options/footerShowPaymentIcon/value/payment.payment.ApplePay?subshopId=deutsch ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "value": true } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "footerShowPaymentIcon", "nodeId": "payment.payment.ApplePay", "value": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Template-Daten. | | 400 Bad Request | | Request-Body konnte nicht als JSON geladen werden. | | 400 Bad Request | | `value` wurde nicht angegeben. | | 400 Bad Request | | `nodeId` fehlt, obwohl die Option ein `attachTo` hat, oder `nodeId` wurde angegeben, obwohl die Option kein `attachTo` hat, oder der Knotentyp von `nodeId` passt nicht zum `attachTo` der Option. | | 400 Bad Request | | `value` entspricht nicht den `constraints` der Option (beispielsweise Wert außerhalb von `min`/`max` oder nicht in `values`). | | 404 Not Found | | Die Option wurde nicht gefunden. | | 404 Not Found | | Der durch `nodeId` referenzierte Konfigurationsknoten existiert nicht. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Templatekompilierung Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-templatekompilierung Template-Kompilierung im Shop über die Admin Interface API starten, ihren Fortschritt überwachen und vergangene Kompilierungsläufe einsehen. Der Endpunkt `/templates` stellt eine Schnittstelle zur Verwaltung der Template-Kompilierung im Shop-System bereit. Über diese Schnittstelle können Sie den Kompilierungsvorgang starten, den aktuellen Fortschritt und Status abfragen sowie eine Liste vergangener Kompilierungsergebnisse einsehen. Zusätzlich lässt sich ermitteln, wie viele Schritte für den vollständigen Kompilierungsprozess erforderlich sind. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | ------------------------ | ------------- | --------------------- | --------------------- | ------------------- | ------------------- | | **Templatekompilierung** | templates/ | | | | | ## Datenfelder für die Templatekompilierung | **Name** | **Typ** | **Bedeutung** | | ------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **createdAt** | String | Zeitpunkt des Kompiliervorgangs (ISO 8601-Format, UTC). | | **diagnostics** | Objekt | Detaillierte Meldungen und Hinweise zu Fehlern oder Warnungen (z. B. fehlende Textbausteine). | | **durationMillis** | Integer | Dauer der Kompilierung in Millisekunden. | | **errorCount** | Integer | Anzahl der aufgetretenen Fehler | | **status** | String | Ergebnisstatus des Vorgangs (z. B. `success`, `error`) | | **subshopId** | String | ID des Subshops, dessen Templates kompiliert wurden | | **userId** | Integer | ID des Nutzers, der die Kompilierung gestartet hat | | **userName** | String | Anzeigename des Nutzers, der die Kompilierung gestartet hat. Entweder Vor- + Nachname oder “WEBSALE”, falls es sich um ein Konto handelt, das WEBSALE gehört. | | **warningCount** | Integer | Anzahl der aufgetretenen Warnungen | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-04-08T11:06:43.000Z", "diagnostics": { "compilation": [ { "column": 33, "file": "/views/contact.htm", "line": 141, "message": "Function with name 'formFields' does not exist", "type": "error" }, ... ], "translation": [] }, "durationMillis": 1800, "errorCount": 5, "status": "error", "subshopId": "deutsch", "userId": 1, "userName": " ", "warningCount": 0 } ``` ## Methoden für die Templatekompilierung Die folgenden Methoden ermöglichen es, den Kompilierungsprozess der Templates zu starten, den Fortschritt zu überwachen und vergangene Kompilierungsergebnisse einzusehen. ### GET templates/results Mit dieser Methode können Sie auf eine Liste der bisherigen Kompiliervorgänge für Templates zugreifen. Jeder Eintrag enthält Angaben zum Status, zur Dauer, zur Anzahl von Fehlern und Warnungen sowie zu den verwendeten Subshops und Nutzern. Die Ergebnisse können gefiltert und sortiert werden, um gezielt bestimmte Kompiliervorgänge zu analysieren. Damit der Endpunkt verwendet werden kann, müssen die entsprechenden Berechtigungen zum Lesen von Template-Daten vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/templates/results ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "createdAt": "2025-02-11T08:52:22.000Z", "diagnostics": { "compilation": [], "translation": [] }, "durationMillis": 4233, "errorCount": 0, "status": "success", "subshopId": "english", "userId": 1, "userName": " ", "warningCount": 0 }, ... ], "nextPageToken": "NQ", "totalCount": 6 } ``` #### Filterfelder `createdAt`, `duration`, `errorCount`, `warningCount`, `user`, `subshopId` #### Sortierfelder `createdAt`, `duration`, `durationMillis`, `errorCount`, `warningCount`, `subshopId`, `status` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | ------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Template-Daten. | | 400 Bad Request | "invalidValue" | `size` ∉ \[1;300]
    `pageToken` ist keine Zahl oder kleiner als 0. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET templates/compilationSteps Mit dieser Methode erhalten Sie die Gesamtanzahl der Kompilierungsschritte, die beim Erstellen der Templates durchgeführt werden. Dabei wird jeder Template-Datei ein fester Dreierschritt zugeordnet: Übersetzen, Parsen und Linken. Die Antwort gibt also die Anzahl der Dateien × 3 zurück. Damit der Endpunkt verwendet werden kann, müssen die entsprechenden Berechtigungen zum Lesen von Template-Daten vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/templates/compilationSteps ``` #### Antwort In diesem Beispiel wurden 4 Templates verarbeitet, wobei jeder Kompilierungsvorgang aus 3 Schritten besteht (Übersetzen, Parsen, Linken), was insgesamt 12 Schritte ergibt. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "compilationSteps": 12 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Template-Daten. | | 503 Service Unavailable | "internalError" | Template-Dateien konnten nicht gelesen werden. | ### GET templates/compile Diese Methode gibt den aktuellen Status des laufenden Kompilierungsvorgangs zurück. Solange die Kompilierung noch nicht abgeschlossen ist, enthält die Antwort Informationen über den Fortschritt. Nach Abschluss liefert der Endpunkt zusätzlich Details zu möglichen Warnungen oder Fehlern. Die Statusabfrage bezieht sich auf einen einzelnen Subshop. Für Shops mit mehreren Subshops muss der gewünschte Subshop über den Parameter `subshopId` in der Anfrage angegeben werden, ohne Angabe wird der Standard-Subshop verwendet. Bei mehreren Subshops muss `GET templates/compile` für jeden Subshop separat aufgerufen werden. Um diese Methode verwenden zu können, müssen entsprechende Berechtigungen zum Lesen von Template-Daten vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/templates/compile ``` #### Antwort (die Kompilierung ist noch nicht fertig) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "current": 240, "progress": 0, "running": true, "total": 240 } ``` #### Antwort (die Kompilierung ist fertig) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "diagnostics": { "compilation": [], "translation": [] }, "errorCount": 0, "running": false, "warningCount": 0 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Template-Daten. | | 503 Service Unavailable | "internalError" | Der Server hat ungültige Daten gefunden. | ### POST templates/compile Diese Methode startet die Kompilierung und Veröffentlichung aller Templates. Dabei werden die aktuellen Textbausteine berücksichtigt und in die Templates eingebunden. Die Kompilierung bezieht sich auf einen einzelnen Subshop. Für Shops mit mehreren Subshops muss der gewünschte Subshop über den Parameter `subshopId` in der Anfrage angegeben werden, ohne Angabe wird der Standard-Subshop verwendet. Bei mehreren Subshops muss `POST templates/compile` für jeden Subshop separat aufgerufen werden. Um diesen Vorgang auszulösen, müssen entsprechende Berechtigungen zum Veröffentlichen von Template-Daten vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/templates/compile ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | -------------------- | -------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Veröffentlichen von Template-Daten. | | 503 Service Unavailable | "serviceUnavailable" | `TemplateCompilerUrl` konnte nicht gefunden werden, oder das Kompilieren ist fehlgeschlagen. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Textbausteine Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-textbausteine Sprachabhängige Textbausteine für Templates über die Admin Interface API abrufen, bearbeiten, löschen und Änderungen im Shop publizieren. Der Endpunkt `/text` stellt eine Schnittstelle zur Verwaltung von Textbausteinen in unserem Shopsystem bereit. Darüber können Sie sprachspezifische Variablen definieren, die innerhalb von Templates verwendet werden. Änderungen an diesen Texten können bequem über das Admin-Interface oder automatisiert per API vorgenommen werden, ohne dass die Templates selbst angepasst werden müssen. Zusätzlich bietet die Schnittstelle Funktionen zum Abrufen, Bearbeiten und Löschen einzelner Textbausteine sowie zum Publizieren der Änderungen. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | --------------------------------- | ---------------------------------- | --------------------- | --------------------- | --------------------- | --------------------- | | **Textbausteine** | text | | | | | | **Namespaces** | text/namespaces | | | | | | **Sprachversion einer Variablen** | `text/{id}/languages/{languageId}` | | | | | | **Publizieren** | text/publish | | | | | ## Datenfelder eines Textbausteins | **Name** | **Typ** | **Bedeutung** | | ------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | **variable** | String | Name der Textvariablen, über die der Inhalt im Template angesprochen wird. | | **translations** | Objekt | Array von Textbausteindaten | | **translations**.**id** | String | Eindeutiger Index des Textbausteins in der Datenbank (fortlaufende Nummer). | | **translations**.**text** | String | Der tatsächliche Inhalt des Textbausteins (z. B. ein Hinweistext oder eine Überschrift). | | **translations**.**languageId** | String | Sprachcode (z. B. `DE`, `EN`) der Sprache, zu der dieser Textbaustein gehört. | | **translations**.**author** | Integer | ID des Benutzers, der die letzte Änderung an diesem Eintrag vorgenommen hat. | | **translations**.**system** | Boolean | Gibt an, ob der Textbaustein standardmäßig vom System bereitgestellt wird. | | **translations**.**used** | Boolean | Wird auf `true` gesetzt, wenn der Textbaustein in einem Template verwendet wurde. | | **translations**.**changedAt** | String | Zeitpunkt der letzten Änderung des Textbausteins (ISO 8601-Format, UTC). | | **translations**.**configReferences** | Integer | Anzahl der Konfigurationsreferenzen, die auf diesen Textbaustein verweisen. Ist der Wert größer als 0, kann der Textbaustein nicht gelöscht werden. | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "translations": { "DE": { "author": 3, "changedAt": "2025-04-01T14:23:00Z", "configReferences": 0, "id": "42", "languageId": "DE", "system": true, "text": "In den Warenkorb", "used": true }, "EN": { "author": 3, "changedAt": "2025-04-01T14:23:00Z", "configReferences": 0, "id": "43", "languageId": "EN", "system": true, "text": "Add to cart", "used": true } }, "variable": "button.addToCart" } ``` ## Methoden für Textbausteine Die hier dokumentierten Methoden bieten eine Schnittstelle zur Verwaltung von Textbausteinen im Shop-System. Sie ermöglichen das Laden, Erstellen, Aktualisieren und Löschen von Variablen, die sprachabhängige Texte enthalten – beispielsweise für Buttons, Fehlermeldungen oder andere UI-Elemente. Jeder Textbaustein kann in mehreren Sprachen vorliegen. Um diese Methoden nutzen zu können, müssen entsprechende Berechtigungen zum Lesen, Schreiben, Erstellen oder Löschen von Textbausteinen vorhanden sein. ### 3.1 GET text Mit dieser Methode wird eine Liste aller verfügbaren Textbausteine inklusive ihrer Übersetzungen geladen. Jeder Eintrag enthält die zugehörige Variable sowie die vorhandenen Sprachversionen mit zusätzlichen Metainformationen wie Änderungszeitpunkt und Autor. Damit der Endpunkt verwendet werden kann, müssen die entsprechenden Berechtigungen zum Lesen von Textbausteinen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/text ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "translations": { "DE": { "author": 3, "changedAt": "2025-04-01T14:23:00Z", "configReferences": 0, "id": "42", "languageId": "DE", "system": true, "text": "In den Warenkorb", "used": true }, "EN": { "author": 3, "changedAt": "2025-04-01T14:23:00Z", "configReferences": 0, "id": "43", "languageId": "EN", "system": true, "text": "Add to cart", "used": true } }, "variable": "button.addToCart" } ], "nextPageToken": "MTAw", "totalCount": 1 } ``` #### Filterfelder `variable`, `text`, `author`, `system`, `used`, `changedAt` #### Sortierfelder `variable`, `text`, `languageId`, `author`, `system`, `changedAt` (das Feld `used` ist nur filterbar, nicht sortierbar, da es zur Laufzeit aus der Template-Nutzung abgeleitet wird) #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | ------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Textbausteinen. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | ### GET text/authors Mit dieser Methode wird eine Liste der Benutzer-IDs zurückgegeben, die mindestens einen Textbaustein bearbeitet haben. Die Daten können beispielsweise zur Filterung oder Analyse der Autorenaktivität verwendet werden. Damit der Endpunkt verwendet werden kann, müssen die entsprechenden Berechtigungen zum Lesen von Textbausteinen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/text/authors ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "author": "1" } ], "totalCount": 1 } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Textbausteinen. | ### GET text/namespaces Mit dieser Methode wird die Liste der eindeutigen Namespaces (Punkt-Präfixe) aller Textbaustein-Variablen abgerufen, beispielsweise `button` oder `footer` bei einer Variablen wie `button.addToCart`. Damit der Endpunkt verwendet werden kann, müssen die entsprechenden Berechtigungen zum Lesen von Textbausteinen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/text/namespaces ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ "button", "footer" ] } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Textbausteinen. | ### GET text/\{id} Mit dieser Methode werden alle Übersetzungen eines bestimmten Textbausteins geladen, identifiziert über den Namen der Variable. Für jede Sprache wird ein eigener Eintrag mit Informationen wie Textinhalt, Bearbeiter und Änderungszeitpunkt zurückgegeben. Damit der Endpunkt verwendet werden kann, müssen die entsprechenden Berechtigungen zum Lesen von Textbausteinen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/text/button.addToCart ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "author": 1, "changedAt": "2025-02-17T11:46:54.000Z", "configReferences": 0, "id": "39", "languageId": "DE", "system": false, "text": "In den Warenkorb", "used": true }, { "author": 1, "changedAt": "2024-12-18T14:44:54.000Z", "configReferences": 0, "id": "40", "languageId": "EN", "system": false, "text": "Add to cart", "used": true } ] ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------- | ------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Textbausteinen. | ### POST text Mit dieser Methode kann eine neue Textvariable mit mehreren Sprachversionen erstellt werden. Dabei werden der Name der Variable `name` und mindestens ein Sprachobjekt mit Sprache `data.languageId` und Text `data.text` übergeben. Die Variable muss eindeutig sein – ein Eintrag mit gleichem Namen darf noch nicht existieren. Damit der Endpunkt verwendet werden kann, müssen die entsprechenden Berechtigungen zum Erstellen von Textbausteinen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/text ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "button.addToCart", "data": [ { "languageId": "DE", "text": "In den Warenkorb" }, { "languageId": "EN", "text": "Add to cart" } ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "author": 1, "changedAt": "2025-02-17T11:46:54.000Z", "configReferences": 0, "id": "39", "languageId": "DE", "system": false, "text": "In den Warenkorb", "used": false }, { "author": 1, "changedAt": "2025-02-17T11:46:54.000Z", "configReferences": 0, "id": "40", "languageId": "EN", "system": false, "text": "Add to cart", "used": false } ] ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | ------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Textbausteinen. | | 400 Bad Request | | Request body konnte nicht geladen werden oder die Variable nicht erzeugt werden. | | 400 Bad Request | "invalidValue" | `name` oder `data.languageId` ist ein leerer String, oder ein data-Element ist kein Objekt. | | 400 Bad Request | "invalidFormat" | `name`, `data.languageId` oder `data.text` sind keine Strings, oder `data` ist kein Array. | | 400 Bad Request | "invalidCharacters" | Der Variablenname enthält ungültige Zeichen. | | 400 Bad Request | "missing" | `name`, `data`, `data.languageId` oder `data.text` wurden nicht angegeben. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body oder in einem data-Element übergeben. | | 409 Conflict | | Eine Variable mit dem selben Namen existiert bereits. | ### POST text/\{id}/duplicate Mit dieser Methode kann eine vorhandene Textvariable dupliziert werden. Dabei werden alle Sprachversionen und Eigenschaften der Originalvariable übernommen. Der Name der neuen Variable wird automatisch generiert, indem an das Ende des ursprünglichen Namens eine Nummer angehängt wird. Falls der Ursprungsname noch keine Zahl am Ende enthält, wird die Ziffer **1** hinzugefügt (beispielsweise wird aus „titel“ der Name „titel1“). Falls der Name bereits auf eine Zahl endet, wird ab dieser Zahl aufwärts nach der nächsten freien Zahl gesucht (nicht ab 1). Beispiel: Gibt es bereits Variablen mit den Namen „x1“ bis „x9“ und wird „x1“ dupliziert, entsteht „x10“. Fehlt „x4“ und wird eine Variable mit einer Zahl bis einschließlich 3 dupliziert (beispielsweise „x1“), entsteht „x4“. Wird stattdessen eine Variable mit einer höheren Zahl dupliziert (beispielsweise „x6“), bleibt die Lücke bei „x4“ ungefüllt, und es entsteht stattdessen die nächste freie Zahl ab „x7“. Die neue Variable ist eindeutig und kann unabhängig von der Originalvariablen weiterverwendet oder bearbeitet werden. Damit der Endpunkt verwendet werden kann, müssen die entsprechenden Berechtigungen zum Erstellen von Textbausteinen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/text/button.addToCart/duplicate ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "translations": { "DE": { "author": 1, "changedAt": "2025-02-17T11:46:54.000Z", "configReferences": 0, "id": "41", "languageId": "DE", "system": false, "text": "In den Warenkorb", "used": false }, "EN": { "author": 1, "changedAt": "2025-02-17T11:46:54.000Z", "configReferences": 0, "id": "42", "languageId": "EN", "system": false, "text": "Add to cart", "used": false } }, "variable": "button.addToCart1" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ----------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Erstellen von Textbausteinen. | | 404 Not Found | | Variable mit `variable`=`{id}` wurde nicht gefunden. | | 503 Service Unavailable | "internalError" | Das Duplizieren ist fehlgeschlagen. | ### PUT text/\{id} Mit dieser Methode können bestehende Textbausteine einer Variable aktualisiert oder die Variable selbst umbenannt werden. Es ist möglich, Übersetzungen für eine oder mehrere Sprachen zu ändern – nicht angegebene Sprachen bleiben unverändert. Damit der Endpunkt verwendet werden kann, müssen die entsprechenden Berechtigungen zum Schreiben von Textbausteinen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/text/button.addToCart ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "button.addToCart", "data": [ { "languageId": "EN", "text": "Buy now" } ] } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "author": 1, "changedAt": "2025-02-17T11:46:54.000Z", "configReferences": 0, "id": "39", "languageId": "DE", "system": false, "text": "In den Warenkorb", "used": false }, { "author": 1, "changedAt": "2025-04-30T14:10:12.000Z", "configReferences": 0, "id": "40", "languageId": "EN", "system": false, "text": "Buy now", "used": false } ] ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------------- | ------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Textbausteinen. | | 400 Bad Request | | Request Body konnte nicht geladen werden. | | 400 Bad Request | "invalidValue" | `name` oder `data.languageId` ist ein leerer String, oder ein data-Element ist kein Objekt. | | 400 Bad Request | "invalidFormat" | `name`, `data.languageId` oder `data.text` sind keine Strings, oder `data` ist kein Array. | | 400 Bad Request | "invalidCharacters" | Der neue Variablenname enthält ungültige Zeichen. | | 400 Bad Request | "missing" | `name`, `data` oder `data.languageId` wurden nicht angegeben. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body oder in einem data-Element übergeben. | | 404 Not Found | | Variable mit `variable`=`{id}` wurde nicht gefunden. | | 409 Conflict | | Eine Variable mit dem neuen Namen existiert bereits. | ### DELETE text/\{id} Mit dieser Methode kann eine bestehende Textvariable vollständig gelöscht werden. Dies betrifft alle zugehörigen Übersetzungen in verschiedenen Sprachen.\ Damit der Endpunkt verwendet werden kann, müssen die entsprechenden Berechtigungen zum Löschen von Textbausteinen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/text/button.addToCart ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------ | --------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Textbausteinen. | | 404 Not Found | | Variable mit `variable`=`{id}` wurde nicht gefunden. | | 409 Conflict | "systemText" | Systemtexte können nicht gelöscht werden. | | 409 Conflict | "textInUse" | Die Variable wird noch in einer Konfiguration verwendet und kann nicht gelöscht werden. | ### DELETE text/\{id}/languages/\{languageId} Mit dieser Methode wird nur die Übersetzung einer einzelnen Sprache (`languageId`, beispielsweise `EN`) einer Textvariablen gelöscht. Die Variable selbst und ihre übrigen Sprachversionen bleiben erhalten. Damit der Endpunkt verwendet werden kann, müssen die entsprechenden Berechtigungen zum Löschen von Textbausteinen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/text/button.addToCart/languages/EN ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | ------------ | ----------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Löschen von Textbausteinen. | | 404 Not Found | | Variable oder Sprache wurde nicht gefunden. | | 409 Conflict | "systemText" | Systemtexte können nicht gelöscht werden. | | 409 Conflict | "textInUse" | Die letzte verbleibende Sprache einer noch referenzierten Variablen kann nicht gelöscht werden. | ## Methoden für Publizieren Die folgenden Methoden ermöglichen es, Textbausteine im Shop-System zu publizieren. Dabei wird geprüft, ob ein Publiziervorgang läuft oder ein neuer gestartet werden kann. Um diese Funktionen zu verwenden, müssen entsprechende Berechtigungen zum Publizieren von Textbausteinen vorhanden sein. ### GET text/publish Mit dieser Methode kann geprüft werden, ob aktuell ein Publiziervorgang für Textbausteine läuft. Ist kein Vorgang aktiv, wird zusätzlich das Ergebnis der letzten Kompilierung als `success` zurückgegeben. Das Feld `success` ist nur vorhanden, wenn `running` den Wert `false` hat. Um den Status abzufragen, müssen entsprechende Berechtigungen zum Lesen von Textbausteinen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/text/publish ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "running": false, "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Textbausteinen. | | 503 Service Unavailable | "internalError" | Interner Fehler beim Abrufen des Kompilierungsstatus. | ### POST text/publish Mit dieser Methode werden die Templates des Shops mit den zuletzt geänderten Textbausteinen neu kompiliert. Damit dieser Vorgang gestartet werden kann, müssen die erforderlichen Berechtigungen zum Publizieren von Textbausteinen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www..de/admin/api/v1/text/publish ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "success": true } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------- | ------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Publizieren von Textbausteinen. | | 503 Service Unavailable | | Das Kompilieren der Templates konnte nicht gestartet werden. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Transaktionen Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-transaktionen Zahlungstransaktionen über die Admin Interface API abrufen, Status aktualisieren sowie Erfassung, Rückerstattung oder Abbruch auslösen. Der Endpunkt `transactions/` stellt eine Schnittstelle zur Verfügung, mit der Zahlungsinformationen aus dem Shop-System abgerufen und verwaltet werden können. Zu jeder Transaktion lassen sich Details wie Zahlungsart, Status, Beträge und zeitliche Abläufe einsehen. Darüber hinaus unterstützt die Schnittstelle die Aktualisierung des Status sowie Aktionen wie Erfassung, Rückerstattung oder Abbruch. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **DELETE** | **GET** | **POST** | **PUT** | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------- | ------------------- | --------------------- | ------------------- | --------------------- | | [**Transaktionen**](https://websale.atlassian.net/wiki/spaces/WSDOKU/pages/3058532986/API-Referenz+Templatekompilierung#3-methhttps-websaleatlassiannet-wiki-spaces-wsdoku-pages-3142778881-api-referenztransaktionen3-methoden-für-die-transaktionen) | transactions/ | | | | | ## Datenfelder einer Transaktion | Name | Typ | Bedeutung | | ---------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `accountId` | Integer | ID des Kundenkontos, das die Zahlung durchgeführt hat. | | `amount` | String | Betrag der Transaktion (in der jeweiligen Währung). | | `clearerId` | String | ID des Zahlungsdienstleisters (z. B. PayPal, Klarna). | | `createdAt` | String | Zeitpunkt der Erstellung (ISO 8601-Format, UTC). | | `currency` | String | ISO-Währungscode (z. B. "EUR"). | | `id` | String | Eindeutige ID der Transaktion. | | `orderId` | String | ID der Bestellung, zu der die Transaktion gehört. | | `payedAt` | String | Zeitpunkt der Bezahlung (ISO 8601-Format, UTC). | | `paymentMethod` | String | Bezeichner der gewählten Zahlungsart (z. B. "paypalCheckout"). | | `paymentStatus` | Integer | Status der Bezahlung (z. B. offen, bezahlt, fehlgeschlagen).
    Mögliche Werte:
    `0 = Pending`
    `1 = Finished`
    `2 = Error`
    `3 = Redirected`
    `4 = Canceled`
    `5 = Rejected`
    `6 = CanceledByAdmin`
    `7 = Refunded`
    `8 = RefundedPartially` | | `refundedAt` | String | Zeitpunkt der Rückerstattung (falls erfolgt). | | `sandboxPayment` | Boolean | Gibt an, ob die Transkation mit einer Zahlungsart ausgeführt wurde, die im Sandbox-/-Testmodus konfiguriert war.
    Mögliche Werte:
    `true` = Zahlungsart im Sandbox-Modus
    `false` = Zahlungsart im Live-Modus | | `sessionId` | String | ID der Session, in der die Zahlung erfolgt ist. | | `subshopId` | String | ID des Subshops, in dem die Zahlung stattgefunden hat. | | `updatedAt` | String | Zeitpunkt der letzten Aktualisierung (ISO 8601-Format, UTC). | #### Beispiel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountId": 4, "amount": "23.940000", "clearerId": "paypal-checkout", "createdAt": "2025-03-20T15:20:26Z", "currency": "EUR", "id": "7RL91160EW951091F", "orderId": "1501", "payedAt": "2025-03-20T15:20:26Z", "paymentMethod": "paypalCheckout", "paymentStatus": 1, "refundedAt": "0000-00-00T00:00:00Z", "sessionId": "8ed8455230bf1920dda6fe73c550d72620647ff35cec4fe3cfe6c410fa487cc0", "subshopId": "deutsch", "sandboxPayment": 0, "updatedAt": "2025-03-20T15:20:26Z" } ``` ## Methoden für die Transaktionen Die folgenden Methoden ermöglichen es, Transaktionen im Shop-System zu verwalten. Eine Transaktion erfasst die Zahlungsbewegung zu einer Bestellung und enthält Informationen wie Betrag, Status, Zahlungsart und Zeitpunkte der Zahlung oder Rückerstattung. Über die API können Transaktionen ausgelesen, ihr Status aktualisiert, zurückerstattet, abgebrochen oder erfasst werden. Für alle Methoden müssen entsprechende Berechtigungen zum Lesen oder Schreiben von Transaktionsdaten vorhanden sein. ### GET transactions Mit dem Endpunkt `transactions` können Sie auf eine Liste abgeschlossener Transaktionen im Shop zugreifen. Die API ermöglicht es, Transaktionen nach verschiedenen Kriterien wie Zeiträumen, Zahlungsstatus oder Subshop zu filtern und zu sortieren. Die Transaktionen enthalten unter anderem Informationen zu Beträgen, Zahlungsmethoden, zugehörigen Bestellungen und Kundenkonten. Um auf diesen Endpunkt zuzugreifen, müssen die entsprechenden Berechtigungen zum Lesen von Transaktionsdaten vorhanden sein. #### Beispiel Das Beispiel zeigt eine Abfrage von bis zu 100 Transaktionen, die im Zeitraum vom 23.03.2025 bis einschließlich 22.04.2025 erstellt wurden. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/transactions?size=100&filter_gte[createdAt]=2025-03-23T00:00:00.360Z &filter_lte[createdAt]=2025-04-22T23:59:59.360Z ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "endReached": true, "items": [ { "accountId": 4, "amount": "12.950000", "clearerId": "paypal-checkout", "createdAt": "2025-03-24T08:08:16Z", "currency": "EUR", "id": "86T19828EK510721G", "orderId": "1553", "payedAt": "2025-03-24T08:08:16Z", "paymentMethod": "paypalCheckout", "paymentStatus": 1, "refundedAt": "0000-00-00T00:00:00Z", "sessionId": "3a8a5e026ce14ec37b906654e27f5551aadae6049e4050405b4fc5b295d4db6e", "subshopId": "deutsch", "sandboxPayment": 0, "updatedAt": "2025-03-24T08:08:16Z" }, { "accountId": 117, "amount": "12.950000", "clearerId": "paypal-checkout", "createdAt": "2025-03-24T13:15:25Z", "currency": "EUR", "id": "27V62418RL450684B", "orderId": "1688", "payedAt": "2025-03-24T13:15:25Z", "paymentMethod": "paypalCheckout", "paymentStatus": 1, "refundedAt": "0000-00-00T00:00:00Z", "sessionId": "3bd02f1620965216cefd91eee7c55dba5bf3d036386f40a519304fdeef94dc21", "subshopId": "deutsch", "sandboxPayment": 0, "updatedAt": "2025-03-24T13:15:25Z" } ], "nextPageToken": "MQ", "totalCount": 2 } ``` #### Filterfelder `id`, `createdAt`, `payedAt`, `refundedAt`, `paymentStatus`, `subshopId`, `accountId`, `sandboxPayment` #### Sortierfelder `id`, `createdAt`, `updatedAt`, `payedAt`, `refundedAt`, `paymentStatus`, `subshopId`, `accountId`, `orderId`, `sessionId`, `clearerId`, `currency`, `amount`, `paymentMethod`, `sandboxPayment` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------- | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Transaktionen. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "unknownDataField" | Ein Filter- oder Sortierfeld ist ungültig. | | 400 Bad Request | "unknownOperation" | Ein Filtertyp ist ungültig. | | 400 Bad Request | "invalidCharacters" | `size` ist keine Ganzzahl.
    Ein Filterwert ist ungültig. | | 400 Bad Request | "syntaxError" | `sort` enthält mehr als einen oder keinen ":". | | 503 Service Unavailable | "internalError" | Das Lesen von Daten ist fehlgeschlagen. | ### GET transactions/\{id} Diese Methode lädt die vollständigen Details einer einzelnen Transaktion basierend auf ihrer eindeutigen ID. Sie können damit Transaktionsinformationen wie Zahlungsstatus, Adressen sowie Zusatzdaten abrufen. Damit die Methode verwendet werden kann, müssen die erforderlichen Berechtigungen zum Lesen von Transaktionen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/transactions/86T19828EK510721G ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountId": 4, "amount": "12.950000", "clearerId": "paypal-checkout", "createdAt": "2025-03-24T08:08:16Z", "currency": "EUR", "id": "86T19828EK510721G", "orderId": "1553", "payedAt": "2025-03-24T08:08:16Z", "paymentMethod": "paypalCheckout", "paymentStatus": 1, "refundedAt": "0000-00-00T00:00:00Z", "sessionId": "3a8a5e026ce14ec37b906654e27f5551aadae6049e4050405b4fc5b295d4db6e", "subshopId": "deutsch", "sandboxPayment": 0, "updatedAt": "2025-03-24T08:08:16Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | --------- | ------------------------------------------------------------------------------ | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Transaktionen. | | 404 Not Found | | Die Transaktion wurde nicht gefunden. | | 400 Bad Request | "missing" | `id` fehlt. | ### PUT transactions/\{id}/refresh Mit dieser Methode wird der aktuelle Status einer vorhandenen Transaktion beim angebundenen Zahlungsdienstleister abgefragt und aktualisiert. Sie kann verwendet werden, wenn der Status einer Transaktion nicht mehr aktuell erscheint (z. B. bei ausstehenden Zahlungen oder Rückerstattungen). Es müssen entsprechende Berechtigungen zum Schreiben von Transaktionsdaten vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/transactions/86T19828EK510721G/refresh ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountId": 4, "amount": "12.950000", "clearerId": "paypal-checkout", "createdAt": "2025-03-24T08:08:16Z", "currency": "EUR", "id": "86T19828EK510721G", "orderId": "1553", "payedAt": "2025-03-24T08:08:16Z", "paymentMethod": "paypalCheckout", "paymentStatus": 1, "refundedAt": "0000-00-00T00:00:00Z", "sessionId": "3a8a5e026ce14ec37b906654e27f5551aadae6049e4050405b4fc5b295d4db6e", "subshopId": "deutsch", "sandboxPayment": 0, "updatedAt": "2025-03-24T08:08:16Z" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | --------- | ---------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Transaktionen. | | 400 Bad Request | "missing" | `id` fehlt. | | 404 Not Found | | Die Daten der Transaktion konnten nach der Aktualisierung nicht gelesen werden. | ### PUT transactions/\{id}/cancel Mit dieser Methode wird versucht, eine Transaktion beim angebundenen Zahlungsdienstleister zu stornieren. Dies ist beispielsweise bei noch nicht abgeschlossenen oder fehlerhaften Zahlungen erforderlich. Nach erfolgreicher Stornierung wird die aktualisierte Transaktion zurückgegeben. Es müssen entsprechende Berechtigungen zum Schreiben von Transaktionen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/transactions/86T19828EK510721G/cancel ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountId": 4, "amount": "12.950000", "clearerId": "paypal-checkout", "createdAt": "2025-03-24T08:08:16Z", "currency": "EUR", "id": "86T19828EK510721G", "orderId": "1553", "payedAt": "2025-03-24T08:08:16Z", "paymentMethod": "paypalCheckout", "paymentStatus": 4, "refundedAt": "2025-04-24T10:30:00Z", "sessionId": "3a8a5e026ce14ec37b906654e27f5551aadae6049e4050405b4fc5b295d4db6e", "subshopId": "deutsch", "sandboxPayment": 0, "updatedAt": "2025-04-24T10:30:00Z" } ``` Nach erfolgreicher Stornierung wird der `paymentStatus` in der Regel auf `4` (`Canceled`) oder `6` (`CanceledByAdmin`) gesetzt. Der genaue Wert hängt vom Zahlungsdienstleister ab. #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Transaktionen. | | 404 Not Found | | Die Transaktion wurde nicht gefunden.
    Die Daten der Transaktion konnten nach der Aktualisierung nicht gelesen werden. | | 400 Bad Request | "missing" | `id` fehlt. | | 503 Service Unavailable | "internalError" | Das Abbrechen ist fehlgeschlagen.
    Die Transaktion konnte nach der Aktualisierung nicht geladen werden. | ### PUT transactions/\{id}/refund Diese Methode löst eine Rückerstattung eines bereits bezahlten Betrags bei der angegebenen Transaktion aus. Optional kann ein Teilbetrag (`amount`) und ein Rückgabegrund (`reason`) im Request Body übergeben werden. Wird kein Betrag angegeben, wird der gesamte Betrag erstattet. Nach erfolgreicher Rückerstattung wird die aktualisierte Transaktion zurückgegeben. Für diese Aktion müssen entsprechende Berechtigungen zum Schreiben von Transaktionen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/transactions/86T19828EK510721G/refund ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "amount": "5", "reason": "Mein Grund" } ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountId": 2, "amount": "30.990000", "clearerId": "paypal-checkout", "createdAt": "2025-03-18T14:37:51Z", "currency": "EUR", "id": "1MV26007FY832013B", "orderId": "1330", "payedAt": "2025-03-18T14:37:51Z", "paymentMethod": "paypalCheckout", "paymentStatus": 7, "refundedAt": "2025-03-18T15:16:59Z", "sessionId": "ba068bace905c4ce9a32219e2170af2f69a959dd6a59d7b9909718885d259c4a", "subshopId": "deutsch", "sandboxPayment": 0, "updatedAt": "2025-03-18T15:16:59Z" } ``` Nach erfolgreicher Rückerstattung wird der `paymentStatus` auf `7` (Refunded) oder `8` (RefundedPartially) gesetzt, je nachdem ob der gesamte oder ein Teilbetrag erstattet wurde. #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Transaktionen. | | 400 Bad Request | | Request body konnte nicht geladen werden. | | 404 Not Found | | Die Transaktion wurde nicht gefunden.
    Die Daten der Transaktion konnten nach der Aktualisierung nicht gelesen werden. | | 400 Bad Request | "missing" | `id` fehlt. | | 400 Bad Request | "invalidValue" | `amount` ist ≤ 0 oder größer als der Betrag der Transaktion. | | 400 Bad Request | "invalidFormat" | `amount` oder `reason` ist kein String. | | 400 Bad Request | "unknownDataField" | Ein unbekanntes Feld wurde im Request Body übergeben. | | 503 Service Unavailable | "internalError" | Das Erstatten ist fehlgeschlagen.
    Die Transaktion konnte nach der Aktualisierung nicht geladen werden. | ### PUT transactions/\{id}/capture Diese Methode dient dazu, eine reservierte Transaktion zu erfassen, d. h. der ursprünglich nur vorgemerkte Betrag wird final vom Kundenkonto abgebucht. Diese Funktion wird vor allem bei Zahlungsanbietern benötigt, bei denen eine Autorisierung und eine separate Erfassung erforderlich sind (z. B. Kreditkarte). Die aktualisierte Transaktion wird im Anschluss zurückgegeben. Für diese Aktion müssen entsprechende Berechtigungen zum Schreiben von Transaktionen vorhanden sein. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/transactions/86T19828EK510721G/capture ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountId": 4, "amount": "12.950000", "clearerId": "paypal-checkout", "createdAt": "2025-03-24T08:08:16Z", "currency": "EUR", "id": "86T19828EK510721G", "orderId": "1553", "payedAt": "2025-04-24T11:05:00Z", "paymentMethod": "paypalCheckout", "paymentStatus": 2, "refundedAt": "0000-00-00T00:00:00Z", "sessionId": "3a8a5e026ce14ec37b906654e27f5551aadae6049e4050405b4fc5b295d4db6e", "subshopId": "deutsch", "sandboxPayment": 0, "updatedAt": "2025-04-24T11:05:00Z" } ``` Nach erfolgreicher Erfassung wird der `paymentStatus` in der Regel auf `1` (Finished) gesetzt. Bei einem Fehler wird er auf `2` (Error) gesetzt. #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben von Transaktionen. | | 404 Not Found | | Die Transaktion wurde nicht gefunden.
    Die Daten der Transaktion konnten nach der Aktualisierung nicht gelesen werden. | | 400 Bad Request | "missing" | `id` fehlt. | | 503 Service Unavailable | "internalError" | Das Erfassen ist fehlgeschlagen.
    Die Transaktion konnte nach der Aktualisierung nicht geladen werden. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Videos Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-videos Videos über die Admin Interface API in den Shop hochladen, ihre URLs abfragen und konfigurierbare Format- und Größenbeschränkungen nutzen. Der Endpunkt `videos/` stellt eine Schnittstelle zur Verwaltung von Videos im Shop-System bereit. Über die API können Videos hochgeladen und die zugehörigen URLs abgefragt werden. Unterstützt werden verschiedene Videoformate sowie individuelle Einschränkungen wie maximale Dateigröße und erlaubte Formate, die über die Shop-Konfiguration `content.videoSettings` gesteuert werden. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | ---------------- | ------------------------ | --------------------- | ------------------- | --------------------- | ------------------- | | **Video URL** | `videos/url/{typeId}` | | | | | | **Video Upload** | `videos/upload/{typeId}` | | | | | ## Allgemein * **Unterstützte Videoformate:** * `mp4` * `avi` * `mov` * `wmv` * `flv` * `mkv` * `webm` * `mpeg` * `3gp` * `ogg/ogv` * **Maximale Dateigröße**\ Wird über die Konfiguration `content.videoSettings` festgelegt. * **Erlaubte Formate**\ Die zulässigen Videoformate können ebenfalls über `content.videoSettings` konfiguriert werden. ## Methoden für Video Upload ### GET videos/url/\{typeId} Dieser Endpunkt liefert die URL, unter der Videos des angegebenen Typs (z. B. Kategorie- oder Produktvideos) gespeichert werden. Der Pfadparameter `typeId` muss den Wert `categories` oder `products` haben. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/videos/url/categories ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "url": "//content.myshop.localhost/categories/video" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ---------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Lesen von Kategorie- oder Produkt-Daten. | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "missing" | `subshopId` wurde nicht übergeben. | ### POST videos/upload/\{typeId} Dieser Endpunkt ermöglicht das Hochladen eines Videos für einen angegebenen Typ (z. B. Kategorien oder Produkte). Der Pfadparameter `typeId` muss den Wert `categories` oder `products` haben. Der Request-Body muss den Dateinamen (`fileName`) sowie die Binärdaten des Videos (`videoData`) enthalten. Nach einem erfolgreichen Upload wird der Name der hochgeladenen Datei zurückgegeben. Schreibberechtigungen für Kategorie- oder Produktdaten sind erforderlich. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://www..de/admin/api/v1/videos/upload/categories?subshopId=deutsch ``` #### Request Body ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Content-Type: multipart/form-data fileName: myVideo.mp4 videoData: ``` #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "newFile": "myVideo.mp4" } ``` #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ----------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 403 Forbidden | | Sie verfügen nicht über die erforderlichen Rechte zum Schreiben Kategorie- oder Produkt-Daten. | | 400 Bad Request | "missing" | `subshopId` wurde nicht übergeben.
    `video` wurde nicht übergeben (wenn `fileName` oder `videoData` fehlen oder leer sind). | | 400 Bad Request | "invalidValue" | | | 400 Bad Request | "invalidFileFormat" | Das Video hat ein ungültiges Format. | | 503 Service Unavailable | "internalError" | Das Hochladen ist fehlgeschlagen. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # API-Referenz Wechselkurse Source: https://dokumentation.websale.de/schnittstellen/admin-interface-api/api-referenz-wechselkurse Umrechnungskurse für die Anzeige-Währungsumrechnung über die Admin Interface API abrufen: Kurs-Bundle relativ zu einer Zielwährung inklusive Aktualitäts-Kennzeichen. Der Endpunkt `exchange-rates` liefert ein Bündel aktueller Wechselkurse, mit dem sich Beträge aus beliebigen bekannten Währungen in eine frei wählbare Zielwährung umrechnen lassen. Die Kurse basieren auf den von der Europäischen Zentralbank (EZB) bezogenen Referenzkursen. Intern werden diese Kurse relativ zur Basiswährung **EUR** gespeichert; der Endpunkt berechnet daraus die Kreuzkurse zur angefragten Zielwährung. Genutzt wird die Schnittstelle unter anderem vom Admin Interface, um Beträge lokal in der gewählten Anzeige-Währung darzustellen, ohne dass für jede Umrechnung eine separate Anfrage nötig ist. Die Wechselkurse werden täglich von der EZB abgerufen. Der Endpunkt liefert dabei stets den aktuellsten dem Shop bekannten Wechselkurs zurück. Für die Nutzung dieses Endpunkts ist eine gültige Anmeldung erforderlich (siehe [API Basics](/schnittstellen/admin-interface-api/api-basics)). Eine servicespezifische Berechtigung wird nicht benötigt. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | ---------------- | -------------- | --------------------- | ------------------- | ------------------- | ------------------- | | **Wechselkurse** | exchange-rates | | | | | ## Datenfelder eines Kurseintrags Jeder Eintrag im Objekt `rates` beschreibt den Umrechnungskurs einer Währung in die angefragte Zielwährung. | **Name** | **Typ** | **Verwendung** | | ------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **rate** | Number | Umrechnungsfaktor in die Zielwährung. Ein Betrag in der jeweiligen Währung wird durch Multiplikation mit `rate` in die Zielwährung umgerechnet (`Betrag_Zielwährung = Betrag_Ausgangswährung × rate`). Die Zielwährung selbst hat immer den Wert `1.0`. | | **rateDate** | String | Datum des zugrunde liegenden EZB-Kurses (Format `YYYY-MM-DD`). Bei Kreuzkursen wird das ältere der beiden beteiligten Kursdaten (Ausgangs- und Zielwährung) verwendet. | | **isRecent** | Boolean | Gibt an, ob der Kurs den konfigurierten Aktualitätsvorgaben entspricht (`true`). Bei `false` konnte kein hinreichend aktueller Kurs ermittelt werden – der Wert wird dennoch zurückgegeben, sollte aber mit Vorsicht verwendet werden. | Die Basiswährung **EUR** ist immer im Ergebnis enthalten, auch wenn für sie kein eigener Kurssatz in der Datenbank vorliegt. Sie besitzt implizit den Kurs `1.0` mit dem aktuellen Datum. ## Methoden für Wechselkurse ### GET exchange-rates Mit diesem Endpunkt wird ein Bündel von Umrechnungskursen relativ zu einer Zielwährung abgerufen. Die Zielwährung wird über den Pflichtparameter `target` als dreistelliger ISO-4217-Währungscode (z. B. `EUR`, `USD`, `GBP`) übergeben. Die Antwort enthält für jede im System bekannte Währung einen Kurseintrag sowie zusätzlich die Zielwährung selbst (mit Kurs `1.0`). Ist für die angefragte Zielwährung selbst kein Kurs zu EUR bekannt (beispielsweise bei nicht unterstützten ISO-Codes), enthält die Antwort ausschließlich den Eintrag der Zielwährung mit Kurs `1.0`. Alle übrigen Währungen fehlen dann in `rates`. #### Beispiel ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.de/admin/api/v1/exchange-rates?target=EUR ``` #### Unterstützte Parameter | **Parameter** | **Beschreibung** | | ------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `target` | **Pflichtfeld.** Dreistelliger ISO-4217-Code der Zielwährung, in die umgerechnet werden soll. Muss exakt drei Zeichen lang sein. | #### Antwort ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "target": "EUR", "rates": { "EUR": { "rate": 1.0, "rateDate": "2026-07-02", "isRecent": true }, "GBP": { "rate": 1.18203, "rateDate": "2026-07-01", "isRecent": true }, "USD": { "rate": 0.91996, "rateDate": "2026-07-01", "isRecent": true } } } ``` Im Beispiel entspricht `1 USD` etwa `0,92 EUR` und `1 GBP` etwa `1,18 EUR`. Um einen Betrag umzurechnen, wird er mit dem `rate` der Ausgangswährung multipliziert. #### Fehlercodes | **Fehler** | **Typ** | **Grund** | | ---------------- | -------------- | ----------------------------------------------------------------------------- | | 401 Unauthorized | | Nicht autorisiert: Sie sind nicht angemeldet. | | 400 Bad Request | "invalidValue" | Der Parameter `target` fehlt, ist leer oder besitzt nicht exakt drei Zeichen. | ## Support Bei technischen Fragen und Hilfestellungen ist unser Support-Team für Sie erreichbar: [Zum Kundenportal](https://websale.atlassian.net/servicedesk/customer/portal/6) Bitte senden Sie uns eine möglichst detaillierte Beschreibung sowie Screenshots, Requests/Antworten, damit wir Ihre Anfrage zeitnah und zielführend beantworten können. # ASSE-Schnittstelle (Server-Side-Events) Source: https://dokumentation.websale.de/schnittstellen/asse-schnittstelle-server-side-events Asynchrone Server-Side-Events (ASSE) im WEBSALE Shop konfigurieren und auslösen, um Daten per HTTPS an externe Systeme zu übermitteln. Über die ASSE-Schnittstelle (Asynchronous-Server-Side-Events) können beliebige Daten aus dem Shop asynchron per HTTPS an externe Systeme übermittelt werden (z. B. Newsletter-, Such- oder Tracking-Dienste). Die Übertragung erfolgt serverseitig (Shop-Server → Empfänger-Server) und unabhängig vom Client. Es gibt keinen klassischen API-Endpunkt, der von extern „aufgerufen“ wird. Stattdessen wird ein konfiguriertes Event im Shop ausgelöst, das einen asynchronen HTTP-Request an eine definierte Ziel-URL ausführt. *** ## Bereitstellung im Shop Die ASSE-Schnittstelle ist standardmäßig Bestandteil jedes WEBSALE Shops und kann grundsätzlich genutzt werden. ODER ASSE muss im Shop (optional pro Subshop) freigeschaltet/aktiviert sein. *** ## Funktionsweise * Die Übertragung erfolgt serverseitig vom Shop-Server an den Empfänger-Server (nicht vom Client/Brower aus) * Die Kommunikation erfolgt ausschließlich per HTTPS * Die Ausführung ist asynchron: das Auslösen blockiert den Shop-Prozess nicht, auch wenn das Zielsystem nicht reagiert * Es können mehrere Events/Ziele konfiguriert werden * Je Event kann die Übertragung per HTTP-Request mit unterschiedlicher Methode erfolgen (z. B. GET/POST/PUT) *** ## Event-Konfiguration Für die ASSE-Schnittstelle können beliebig viele Events konfiguriert werden. Jedes Event wird über eine Event-ID eindeutig adressiert (diese ID wird beim Auslösen verwendet). Die Konfiguration erfolgt über den Konfigurationsknoten [general.asse](https://websaleag-44ee7ea6.mintlify.app/konfiguration/general-allgemeine-shopeinstellungen#4-general-asse-schnittstelle-für-asynchronous-server-side-events-asse) *** ## Verwendung in Templates (Kurzüberblick) In Templates steht das Modul [\$wsAsse](/frontend/referenz/module/wsasse) zur Verfügung. Mit `$wsAsse.fire(, )` wird ein Event ausgelöst und ein asynchroner HTTP-Request anhand der hinterlegten Event-Konfiguration ausgeführt. * Rückgabe: `true`, wenn das Event erfolgreich getriggert wurde; `false` bei Konfigurationsproblemen. `true` bedeutet dabei aber nicht, dass der Request bereits erfolgreich beim Empfänger angekommen ist (asynchron). * `data` wird nicht URL-encoded (muss bei Bedarf manuell erfolgen) * Wenn eine Liste oder ein Objekt übergeben wird, wird es als JSON konvertiert ### Konfigurierte Events auflisten (Event-IDs ermitteln) Wenn die Event-ID nicht bekannt ist oder nicht in die Konfiguration geschaut werden soll. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $event in $wsAsse.asseConfigs: print $event.id; /foreach }} ``` ### Event auslösen (fire) Ein Event kann nur ausgelöst werden, wenn es zuvor in der Konfiguration [general.asse](https://websaleag-44ee7ea6.mintlify.app/konfiguration/general-allgemeine-shopeinstellungen#4-general-asse-schnittstelle-für-asynchronous-server-side-events-asse) angelegt wurde. #### Beispiel ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $eventData = "userid=" + $userAccount.id; var $triggered = $wsAsse.fire("myevent", $eventData); }} ``` * Es wird eine Payload aufgebaut: `userid=` * Es wird das konfigurierte Event `myevent` ausgelöst * Der Rückgabewert `true` bedeutet nur: Event wurde getriggert – nicht, dass der HTTP-Request beim Ziel bereits erfolgreich war. * `$eventData` wird nicht automatisch URL-encoded (also z. B. Sonderzeichen/Leerzeichen bei Bedarf vorher selbst kodieren) * Je nach konfigurierter HTTP-Methode wird `$eventData` als Teil der URL (z. B. bei GET) oder als Request-Body (z. B. bei POST/PUT/PATCH) übertragen (laut Tickettext) Mehr Informationen finden Sie in der Modul-Referenz [\$wsAsse](/frontend/referenz/module/wsasse). *** ## Erfolgskriterien, Wiederholungen und Timeouts Da die Übertragung asynchron erfolgt, sind Übertragungsfehler nicht zwingend unmittelbar im Shop sichtbar. Damit die Zustellung als „erfolgreich“ gilt, können Prüfmechanismen / Bedingungen definiert werden (z. B. HTTP-Statuscode, Content-Type oder Response-Inhalte). Wenn Bedingungen nicht erfüllt sind, werden – abhängig von der Konfiguration – Wiederholungsversuche mit Delay und Timeout ausgeführt. Zusätzlich existiert ein serverseitiges Rate-Limit pro Event-ID. Wird es überschritten, liefert `$wsAsse.fire()` `false` und das Event wird nicht in die Warteschlange eingereiht. *** ## Logmanager Inhalt folgt. # Externe Datenschnittstelle (Datei-/Bucket-basiert) Source: https://dokumentation.websale.de/schnittstellen/externe-datenschnittstelle-datei-bucket-basiert Externe Datenschnittstelle in WEBSALE: JSON-Dateien aus S3-Buckets in der Storefront einbinden und über die Template Engine ausgeben. Über die externe Datenschnittstelle können zusätzliche Inhalte und Zusatzdaten (z. B. erweiterte Produkt-/Kategorieinformationen oder CMS-Inhalte) in die WEBSALE Storefront eingebunden werden. Es gibt keinen klassischen API-Endpunkt: Die Daten liegen als Dateien (aktuell JSON) im shopeigenen S3 und werden in der Storefront über die Template Engine gelesen und gerendert. Die Daten dienen somit primär der Ausgabe in Templates und stehen nur in sehr begrenztem Umgang für Shop-Funktionen oder andere dynamische Prozesse zur Verfügung. Weitere Details zur Einbindung und Ausgabe finden sich in der *** ## Bereitstellung im Shop Die externe Datenschnittstelle ist standardmäßig Bestandteil jedes WEBSALE Shops und kann grundsätzlich genutzt werden. Zugangsdaten für den Upload in den S3-Bereich werden nicht automatisch mit dem Shop bereitgestellt, sondern müssen separat über das Beauftragungsportal der WEBSALE AG angefragt werden. *** ## Datenablage im S3 ### Bucket `external-data` In `external-data` werden Dateien abgelegt, die vom Projektteam bereitgestellt werden - z. B. manuell durch den Template-Manager oder automatisiert durch externe Systeme/Programme (z. B. PIM). ### Bucket `system` Der Bucket `system` wird ausschließlich von WEBSALE-Komponenten befüllt. Dazu zählen auch JSON-Daten aus der [WEBSALE Strapi-Instanz](/strapi-cms), die pro Shop standardmäßig bereitgestellt wird.\ `system` ist nicht für eigene Uploads oder für Daten aus externen, kundeneigenen Systemen vorgesehen. *** ## Unterstützte Datenformate Aktuell werden nur Daten im JSON-Format verarbeitet. Weitere Formate können zukünftig ergänzt werden. Bei Bedarf kontaktieren Sie Ihren WEBSALE Ansprechpartner. *** ## Verwendung in der Storefront Die Daten aus den Buckets `external-data` und `system` können in der Storefront über die [Template Engine](/frontend/die-basics/template-engine) eingelesen und ausgegeben werden. Mehr zum Datenzugriff und zur Verwendung in Templates finden Sie [hier](/frontend/referenz/module/wsexternaldata). Für die Einbettung der Daten in das Template wird GitLab benötigt, mehr Infos dazu können [hier](/frontend/getting-started/arbeiten-mit-gitlab) eingesehen werden. # Search API Source: https://dokumentation.websale.de/schnittstellen/search-api HTTPS-Schnittstelle der WEBSALE Search API für Volltextsuche, Filter, Sortierung, Pagination und Suchvorschläge (Suggest/Autocomplete). Die Search API stellt den HTTPS-basierten Zugriff auf das versionsunabhängige Suchmodul WEBSALE Search bereit. Typische Anwendungsfälle: * Volltextsuche über Produkte, Kategorien und ggf. Content * Filter (Checkbox-Filter, Preisbereiche usw.) * Vorschlagsfunktion (Suggest) mit Suchvorschlägen * Pagination und Sortierung Die Search API ist unabhängig von [Storefront API](/schnittstellen/storefront-api) und [Admin Interface API](/schnittstellen/admin-interface-api) und wird in der Regel parallel dazu eingesetzt. *** ## Basis-URL Alle REST-API-Aufrufe der Suche laufen über dieselbe Basis-URL unter dem Pfad `/api`: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.search.websale.net/api/ ``` #### Beispiele für die Verwendung der Endpoints #### Suche ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.search.websale.net/api/search?query=schuhe&subshop=01-aa&from=0&size=24 ``` #### Suchvorschläge / Autocomplete ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.search.websale.net/api/suggest?query=schu&subshop=01-aa ``` `` muss durch Ihre ShopID / CommonID der für Sie bereitgestellten Shop-Plattform ersetzt werden. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl/Info** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | ----------------------------------------------------------- | ------------- | --------------------- | ------------------- | ------------------- | ------------------- | | Volltextsuche, Kategorie-Navigation, Filterung & Sortierung | search/ | | | | | | Suchvorschläge (Suggest / Autocomplete) | suggest/ | | | | | | Konfigurierte Sortier-Optionen (Labels) | sortLabels/ | | | | | *** ## Datenfelder der Search-Response Die Search-API liefert bei `GET search` ein JSON-Objekt mit mehreren Bereichen für Treffer und Filter. Die verfügbaren Felder in den Ergebnissen hängen von der [Backend-Konfiguration](/ws-search/konfiguration-des-such-moduls) (`display_fields`, `filter_fields`) ab. ### Bereiche für Produkte, Kategorien und Content Dieser Abschnitt beschreibt die Aufteilung der Suchergebnisse in die Bereiche `product`, `category` und `optional content` mit jeweils eigener Trefferliste und Trefferanzahl. Darüber hinaus wird erläutert, welche zusätzlichen Metadaten (z. B. `total,` `filters`, `applied_filters`, `zero_result_filters` und `wssearchdata`) in der Response enthalten sind und wofür sie verwendet werden. #### Beispiel einer Search-Response-Struktur (verkürzt) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "product": { "results": [ { "_id": "123456", "_source": { "name": "Nike Air Max", "price": 129.99, "brand": "Nike", "color": "schwarz", "size": ["41", "42", "43"], "image": "https://example.com/image.jpg", "url": "/product/nike-air-max" } } ], "sub_total": 150 }, "category": { "results": [ { "_id": "cat_001", "_source": { "name": "Laufschuhe", "url": "/category/laufschuhe" } } ], "sub_total": 5 }, "total": 155, "filters": { ... }, "applied_filters": { ... }, "zero_result_filters": ["inventoryamount"], "wssearchdata": "..." } ``` #### Parameterbeschreibungen | **Name** | **Typ** | **Verwendung** | | --------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `product` | object | Ergebnisse der Produkt-Kontext. Enthält eine Trefferliste und die Anzahl der gefundenen Produkte. | | `category` | object | Ergebnisse im Kategorie-Kontext. Enthält eine Trefferliste und die Anzahl der gefundenen Kategorien. | | `content` | object | Ergebnisse im Content-Kontext, z.B. statische Seiten wie Über uns, Ratgeber etc. (optional) | | `total` | int | Gesamtanzahl aller Treffer über alle Indizes / Bereiche hinweg. (Summe aus `product.sub_total`, `category.sub_total` und ggf. `content.sub_total`). | | `filters` | object | Liste der verfügbaren Filter für die aktuelle Suche (beispielsweise Marke, Farbe, Preisbereich) inklusive möglicher Werte und ggf. Min-/Max-Werten. Enthält kein Label, dieses muss clientseitig aus der eigenen Konfiguration/Übersetzung gepflegt werden. | | `applied_filters` | object | Aktuell gesetzte Filter der Anfrage. | | `zero_result_filters` | array | Liste von statischen Filtern, die im aktuellen Kontext zu 0 Treffern führen würden. (z.B. bestimmte Größen oder Farben, für die aktuell keine Produkte gefunden werden). Hinweis: Nur für `WebComponents` relevant. | | `wssearchdata` | string | Zusatzdaten für das WEBSALE-Bekleidungsmodul (z. B. Query- und Farbwerte) Das [WEBSALE Bekleidungsmodul](https://doku.websale.net/index.html?guide_bekleidungsmodul.html) ist eine Funktion, die ausschließlich in der WEBSALE Shopsoftware Version V8s zur Verfügung steht. | Die Bereiche `product`, `category` und optional `content` haben jeweils die gleiche Struktur ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "product": { "results": [ ... ], "sub_total": 150 } ``` | **Name** | **Typ** | **Verwendung** | | ----------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | `results` | array | Liste der einzelnen Treffer in diesem Bereich. Jedes Element im Array repräsentiert z.B. ein Produkt, eine Kategorie oder eine Content-Seite. | | `sub_total` | int | | Einzelnes Ergebnis in `results` (Beispiel verkürzt) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "_id": "123456", "_source": { "name": "Nike Air Max", "price": 129.99, "brand": "Nike", "color": "schwarz", "size": ["41", "42", "43"], "image": "https://example.com/image.jpg", "url": "/product/nike-air-max" } } ``` | **Name** | **Typ** | **Verwendung** | | --------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `_id` | string | Interne ID des Dokuments im Suchindex Dient zur eindeutigen Identifikation des Treffers im Index. | | `_source` | object | Inhalt des Dokuments laut Suchindex. Welche Felder hier enthalten sind, wird über die Konfiguration der `display_fields` gesteuert und ist je Index (Produkt, Kategorie, Content) unterschiedlich. | ### Filter-Informationen ### `filters` `filters` beschreibt, welche Filter für die aktuelle Suche zur Verfügung stehen. Die Struktur ist abhängig vom Filtertyp, z.B. Checkbox, Listbox etc. #### Checkbox-Filter ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "brand": { "values": ["Nike", "Adidas", "Puma"] } ``` #### Range-Filter (z. B. Preis) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "price": { "min": 29.99, "max": 299.99 } ``` Die Filterobjekte enthalten kein Label. Wird ein Anzeigetext benötigt, muss er clientseitig aus der eigenen Konfiguration/Übersetzung gepflegt werden. Die tatsächlich verfügbaren Filterfelder werden im [Backend](/ws-search/konfiguration-des-such-moduls) über `filter_fields` konfiguriert. ### `applied_filters` `applied_filters` spiegelt wider, welche Filter über die URL-Parameter aktuell aktiv sind. #### Struktur ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "applied_filters": { "{field_name}": [ { "op_type": "eq|neq|gte|lte|gt|lt", "value": ["wert1", "wert2"], "field": "{technischer-feldname}" } ] } ``` * `op_type`: verwendeter Operator (z. B. `eq`, `gte`) * `value`: Liste der gesetzten Werte (auch bei einem einzelnen Wert als Array) * `field`: Name des Feldes, auf das sich der Filter bezieht ### `zero_result_filters` `zero_result_filters` enthält die Namen statischer Custom-Filter (z. B. `"inventoryamount"`), die im aktuellen Kontext zu 0 Treffern führen würden. Dabei geht es nicht um dynamische Filter aus dem Parameter `filters`. Diese dynamischen Filter führen per Definition nie zu 0 Ergebnissen.\ 0 Treffer treten nur bei Custom-/statischen Filtern auf, die z. B. über `WebComponents` erstellt werden und immer zur Verfügung stehen – unabhängig von der aktuellen Suche. ### `wssearchdata` `wssearchdata` ist ein technisches Feld für das [WEBSALE Bekleidungsmodul](https://doku.websale.net/index.html?guide_bekleidungsmodul.html) der Shopversion V8s. Es enthält u. a. Informationen zu Query und Farbfiltern und wird dafür genutzt, farbige Variantenbilder auf Produktlisten korrekt zu laden. Für die Anbindung einer eigenen Frontend-Suche kann das Feld in der Regel unverändert an die entsprechenden Skripte übergeben werden. ## Verwendung der Methoden ### GET `api/search` Mit diesem Aufruf werden Suchergebnisse aus dem Suchindex geladen. Der Endpunkt kann sowohl für klassische Volltextsuche als auch für reine Filter-/Kategorie-Navigation (ohne Suchbegriff) verwendet werden. #### **Beispiel-Anfrage** Einfache Suche nach „laufschuhe“ im Subshop `01-aa` ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.search.websale.net/api/search?query=laufschuhe&subshop=01-aa&from=0&size=24 ``` `` ist dabei die Shop-/CommonID der Shop-Plattform - siehe Kapitel 1 zur Basis-URL. #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "product": { "results": [...], "sub_total": 150 }, "category": { "results": [...], "sub_total": 5 }, "content": { "results": [...], "sub_total": 0 }, "total": 155, "filters": { ... }, "applied_filters": { ... }, "zero_result_filters": [ ... ], "wssearchdata": "..." } ``` Details zu den einzelnen Feldern sind im Abschnitt zur [Search-Response-Struktur](#3-datenfelder-der-search-response) beschrieben. #### **Übersicht der Query-Parameter für GET** `api/search` | **Parameter** | **Typ** | **Beschreibung** | | --------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `device` | string | Gerätetyp, optional für Logging, z.B. `desktop`, `mobile`, `tablet` | | `filter_{OPERATOR}[{FIELD_NAME}]` | | Filter werden über separate Query-Parameter mit Operator-Syntax übergeben. - eq → Equals (exakte Übereinstimmung) - neq → Not Equals (Ausschluss) - gte → Greater Than or Equal - lte → Less Than or Equal - gt → Greater Than - lt → Less Than - rm → Remove Für mehrere Werte desselben Filters kann der Parameter mehrfach übergeben werden (ODER-Verknüpfung). Welche Felder als Filter zur Verfügung stehen, legt die [Konfiguration des Such-Moduls](/ws-search/konfiguration-des-such-moduls) über `filter_fields` fest. | | `from` | integer | Offset für Pagination resp. Blätterfunktion (Startposition der Trefferliste) Standard: `0` | | `language` | string | Browser-Sprache, optional für Logging / Auswertung, z.B. `de-DE`, `en-US` | | `sessionid` | string | Session-Tracking-ID, optional für Logging, beispielsweise `sess_abc123` Standard: `unknown` | | `size` | integer | Anzahl der Ergebnisse pro Seite. Standard: `16` | | `sortOrder` | string | Sortierreihenfolge. Konkrete Sortierfelder sind [konfigurationsabhängig](/ws-search/konfiguration-des-such-moduls) (beispielsweise Relevanz, Preis). Standard: `_score_desc` | | `subshop` | string | **Pflichtfeld**. Subshop-Identifier (lowercase). Bestimmt den Suchkontext / Index. Beispiel: `01-aa`. | | `query` | string | Suchbegriff für Volltextsuche. Wenn keine `query` übergeben wird, muss stattdessen ein `filter_eq[catids]` gesetzt sein (Suche auf Kategorie-Ebene). Mindestens einer der Parameter `query` oder `filter_eq[catids]` muss in der Anfrage enthalten sein, zusätzlich zu `subshop`. `query` muss mindestens eine konfigurationsabhängige Mindestlänge (Backend-Konstante `MIN_LEN_QUERY`) haben, kürzere Suchbegriffe liefern eine leere Trefferliste (`total: 0`) statt eines Fehlers. | #### Weitere Beispiel-Aufrufe für GET `api/search` #### Kategorie-Navigation (ohne Suchbegriff) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET /api/search?subshop=01-aa&filter_eq[catids]=electronics&from=0&size=24 ``` * `subshop=01-aa`: verwendet den Suchindex des Subshops `01-aa`. * `filter_eq[catids]=electronics`: beschränkt die Treffer auf die Kategorie `electronics`.\ Hinweis: Bei `Backend-Suchmodul-Versionen < 1.7.x` muss hier der Kategoriename als String (zB. '`electronics`') übergeben werden; ab `Version 1.7.x` wird an dieser Stelle die tatsächliche Kategorie ID erwartet. * `from=0&size=24`: liefert die erste Seite mit bis zu 24 Treffern. * Ergebnis: Kategorie-Navigation in `electronics` ohne Volltextsuchbegriff. #### Filter-Kombinationen (Marke, Preis, Farbe) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET /api/search?query=smartphone&subshop=01-aa&from=0&size=24&sortOrder=price_asc&filter_eq[brand]=Samsung&filter_eq[brand]=Apple&filter_gte[price]=200&filter_lte[price]=800&filter_eq[color]=schwarz ``` * `query=smartphone`: Volltextsuche nach „smartphone“. * `subshop=01-aa`: Suche im Subshop `01-aa`. * `sortOrder=price_asc`: Sortierung nach Preis aufsteigend. * `filter_eq[brand]=Samsung&filter_eq[brand]=Apple`: nur Produkte der Marken Samsung **oder** Apple. * `filter_gte[price]=200&filter_lte[price]=800`: Preisbereich 200–800 (inklusive). * `filter_eq[color]=schwarz`: nur schwarze Produkte. * Ergebnis: gefilterte Smartphone-Suche, preisaufsteigend sortiert. #### Pagination (Seite 2 bei 24 Ergebnissen pro Seite) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET /api/search?query=schuhe&subshop=01-aa&from=24&size=24 ``` * `query=schuhe`: Volltextsuche nach „schuhe“. * `subshop=01-aa`: Suche im Subshop `01-aa`. * `size=24`: 24 Treffer pro Seite. * `from=24`: Überspringt die ersten 24 Treffer → entspricht Seite 2. * Ergebnis: zweite Seite der Suchergebnisse für „schuhe“. #### Negativ-Filter (Farben ausschließen) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET /api/search?query=shirts&subshop=01-aa&filter_neq[color]=weiß&filter_neq[color]=beige ``` * `query=shirts`: Volltextsuche nach „shirts“. * `subshop=01-aa`: Suche im Subshop `01-aa`. * `filter_neq[color]=weiß&filter_neq[color]=beige`: schließt weiße und beige Shirts aus. * Ergebnis: alle Shirt-Treffer, **außer** in den Farben Weiß und Beige. #### Preis-Range mit Sortierung nach Preis ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET /api/search?query=laptop&subshop=01-aa&filter_gte[price]=600&filter_lte[price]=1500&sortOrder=price_asc ``` * `query=laptop`: Volltextsuche nach „laptop“. * `subshop=01-aa`: Suche im Subshop `01-aa`. * `filter_gte[price]=600&filter_lte[price]=1500`: Preisbereich 600–1500 (inklusive). * `sortOrder=price_asc`: Sortierung nach Preis aufsteigend. * Ergebnis: Laptops im Preisbereich 600–1500, günstigste zuerst. ### GET `api/suggest` Der Endpunkt `GET /api/suggest` liefert Suchvorschläge für einen eingegebenen Teil-Suchbegriff. Die Vorschläge basieren primär auf Logdaten (häufig gesuchte Begriffe) und können bei Bedarf um automatisch generierte Completions ergänzt werden. Zusätzlich kann ein Text für Ghost-Text-Vervollständigung zurückgegeben werden. #### Beispiel-Aufruf ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.search.websale.net/api/suggest?query=lauf&subshop=01-aa ``` #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "suggestions": [ { "text": "laufschuhe nike", "hitCount": 150 }, { "text": "laufhose", "hitCount": 89 }, { "text": "laufjacke", "hitCount": 45 } ], "completion": "laufschuhe" } ``` * `suggestions` ist absteigend anhand des Parameters `hitCount` sortiert und sind aus Logdaten generierte Suchvorschläge. Diese werden bei Bedarf mit `completion` aufgefüllt. * `completion` liefert einen Text, mit dem das Suchfeld automatisch hinter dem aktuell eingegebenen Text ergänzt werden kann (Ghost-Text/Auto-Vervollständigung). #### **Übersicht der Query-Parameter für GET** `api/suggest` | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | `query` | string | **Pflichtfeld.** Teil-Suchbegriff, zu dem Vorschläge ermittelt werden sollen, z.B. “lauf” für Vorschläge wie beispielsweise “laufschuhe” und “laufhose”. | | `subshop` | string | **Pflichtfeld.** Subshop-Identifier der Suche. Es muss die SubshopID, z.B. 01-aa, des gewünschten Subshops angegeben werden. | ### GET `api/sortLabels` Der Endpunkt `GET /api/sortLabels` liefert die im Backend konfigurierten Sortier-Optionen (Keys für `sortOrder`) inklusive sprachlicher Labels. #### Beispiel-Aufruf ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.search.websale.net/api/sortLabels?subshop=01-aa ``` #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "sortLabels": [ { "key": "price_asc", "label": "Preis aufsteigend" }, { "key": "price_desc", "label": "Preis absteigend" } ] } ``` #### **Übersicht der Query-Parameter für GET** `api/sortLabels` | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------------------------------------------------------------- | | `subshop` | string | **Pflichtfeld.** Subshop-Identifier, beispielsweise `01-aa`, des gewünschten Subshops. | # Storefront API Source: https://dokumentation.websale.de/schnittstellen/storefront-api Zentrale REST-Storefront API von WEBSALE für Headless-Frontends: Katalog, Warenkorb, Kundenkonto, Gutscheine, Bewertungen und mehr. Die Storefront API steht als zentrale REST-Schnittstelle für Storefronts im WEBSALE-Shopsystem zur Verfügung. Über sie lassen sich Headless-Storefronts, Progressive Web Apps, mobile Anwendungen oder CMS-basierte Frontends anbinden, ohne direkt auf interne Shop-Logik zugreifen zu müssen. Die API deckt typische Storefront-Funktionen ab – von der URL-Auflösung und Katalogdaten über Verfügbarkeit/Lager, Warenkorb und Gutscheine bis hin zu Kundenkonto, Merklisten, Bewertungen, Newsletter und Formularen. Die Storefront API folgt einem REST-Ansatz und nutzt JSON als Standard-Datenformat. Für eine klare Weiterentwicklung stehen Versionierung und Abwärtskompatibilität im Fokus (beispielsweise über Pfade wie `/v1/`, `/v2/`). Je nach Anwendungsfall wird zwischen öffentlichen und authentifizierten Endpunkten unterschieden. Subshops und Mehrmandantenstrukturen werden nativ unterstützt. Für Listenabrufe sind Paging und Filterung vorgesehen, optional ergänzt durch Cache-Header. Die Storefront API benötigt keine eigene API-Authentifizierung. Anfragen laufen im Kontext des öffentlichen Shops. Der Nutzerkontext wird ausschließlich über die Session im HTTP-Header `X-Session` transportiert (siehe [Storefront API Basics](/schnittstellen/storefront-api/storefront-api-basics)). Die Storefront API ist technisch und fachlich von der [Admin Interface API](/schnittstellen/admin-interface-api) getrennt. *** ## Inhaltsverzeichnis * [Storefront API Basics](/schnittstellen/storefront-api/storefront-api-basics) — Die Seite Storefront API Basics beschreibt die grundlegenden technischen Rahmenbedingungen für die Nutzung der Storefront API. Dazu gehören u. a. Basis-URL und Versionierung, Request-/Response-Format (JSON), Authentifizierung sowie allgemeine Konventionen wie Header, Fehlercodes und Paging. * [Storefront API Checkout (In Progress)](/schnittstellen/storefront-api/storefront-api-checkout-in-progress) — Die Storefront API Checkout stellt Funktionen für den Bestell- und Checkout-Prozess bereit. Darüber werden die Schritte abgedeckt, die typischerweise zwischen Warenkorb und Bestellabschluss stattfinden. * [Storefront API Formulare](/schnittstellen/storefront-api/storefront-api-formulare) — Über den API-Endpunkt für Formulare werden die im Shop verfügbaren Online-Formulare bereitgestellt und deren Felder, Pflichtangaben und Validierungen ausgeliefert. Über den Endpunkt können alle Formulare aufgelistet, ein einzelnes Formular oder Feld abgerufen und ausgefüllte Formulare übermittelt werden. * [Storefront API Gutscheine](/schnittstellen/storefront-api/storefront-api-gutscheine) — Die Storefront API Gutscheine ermöglicht es, Gutscheincodes in der Storefront einzulösen und zu entfernen. Die API prüft dabei automatisch, ob ein Code gültig ist, und liefert nach der Einlösung die aktualisierten Warenkorbwerte (z. B. Rabatte und Summen) sowie bei Bedarf Hinweise/Fehlermeldungen zurück. * [Storefront API Katalog](/schnittstellen/storefront-api/storefront-api-katalog) — Die Katalog API stellt die zentralen Informationen für Produkte und Kategorien bereit und bildet damit die Grundlage für Produktdetailseiten, Kategorieseiten und Navigationselemente. Sie liefert Standardattribute (z. B. Name, Beschreibung, Preis), ergänzt um individuelle Produkt- und Kategorieattribute sowie SEO-Informationen wie Meta-Daten und sprechende URLs. * [Storefront API Kundenbewertungen](/schnittstellen/storefront-api/storefront-api-kundenbewertungen) — Die Storefront-API für Kundenbewertungen stellt Funktionen bereit, um Kundenbewertungen zu erstellen, abzurufen, zu aktualisieren, zu löschen und auszuwerten. Darüber hinaus lassen sich z.B. die eigene Bewertung eines eingeloggten Kontos, alle freigegebenen Bewertungen eines Produkts sowie Statistikwerte abfragen. * [Storefront API Kundenkonto](/schnittstellen/storefront-api/storefront-api-kundenkonto) — Die Kundenkonto API stellt die Funktionen für den Bereich „Mein Konto“ bereit. Dazu gehören die Verwaltung persönlicher Daten, Zugangsdaten und Adressen (Adressbuch anlegen/ändern/löschen) sowie typische Account-Prozesse wie E-Mail-Änderung (inklusive Double-Opt-In), Passwort ändern/zurücksetzen („Passwort vergessen“) und das Löschen des Kontos. * [Storefront API Konfigurationen](/schnittstellen/storefront-api/storefront-api-konfigurationen) — Die Konfiguration API liefert plattform- und subshopspezifische Einstellungen, die für Darstellung und Verhalten der Storefront relevant sind. * [Storefront API Lagerbestand](/schnittstellen/storefront-api/storefront-api-lagerbestand) — Die Verfügbarkeit-&-Lager API ergänzt Katalogdaten um Bestands- und Verfügbarkeitsinformationen. Damit lässt sich im Frontend anzeigen, ob ein Produkt und dessen Variante aktuell verfügbar ist oder als ausverkauft gilt, und entsprechende Hinweise können direkt an Produktlisten oder auf Produktdetailseiten ausgegeben werden. * [Storefront API Merkliste](/schnittstellen/storefront-api/storefront-api-merkliste) — Mithilfe der Storefront-API für Merklisten können Produkte gespeichert, verwaltet und später schnell wiedergefunden werden. Sie bietet Endpunkte zum Anlegen, Umbenennen und Löschen von Merklisten sowie zum Hinzufügen und Entfernen einzelner Produkte. * [Storefront API Newsletter](/schnittstellen/storefront-api/storefront-api-newsletter) — Die Newsletter API dient zur Integration von Newsletter-Anmeldungen und -Abmeldungen für das WEBSALE Newsletter-Modul in der Storefront. Sie kann sowohl für eingeloggte Kunden als auch für anonyme Besucher verwendet werden und bildet die üblichen Opt-in/Opt-out-Vorgänge im Frontend ab. - [Storefront API Optionen](/schnittstellen/storefront-api/storefront-api-optionen) — Die Optionen API liefert die Werte von Template-Optionen über die Storefront-API, global oder für Optionen, die per `attachTo` an einen Konfigurationsknoten gebunden sind. - [Storefront API Session-Handling](/schnittstellen/storefront-api/storefront-api-session-handling) — Das Storefront API Session-Handling stellt Funktionen bereit, um Sessions in der Storefront zu erstellen und zu verwalten. Damit lassen sich Benutzerzustände (z. B. anonymer Besuch oder eingeloggter Kunde) sowie sessiongebundene Daten wie Warenkorb und Merkliste konsistent über mehrere Requests hinweg nutzen. - [Storefront API URL-Resolution](/schnittstellen/storefront-api/storefront-api-url-resolution) — Die URL-Resolution API dient dazu, eine Storefront-URL (insbesondere SEO-URLs) auf den passenden Shop-Inhalt aufzulösen. Damit kann das Frontend sein Routing auf sprechenden URLs aufbauen und erhält als Ergebnis, ob die URL beispielsweise zu einem Produkt oder einer Kategorie gehört – inklusive der erforderlichen internen IDs. - [Storefront API Warenkorb](/schnittstellen/storefront-api/storefront-api-warenkorb) — Die Warenkorb API steuert sämtliche Interaktionen rund um den Warenkorb: Artikel können hinzugefügt, Mengen geändert und Positionen entfernt werden. *** ## Ausblick & aktuell noch nicht enthalten Folgende Themen werden in einer späteren Ausbaustufe berücksichtigt: * Checkout-Prozess (Zahlungs- und Versandarten, Bestellabschluss) * Verwaltung gespeicherter Zahlungsdaten * Events & Webhooks * Systemmails (Transactional Messaging API) * Direktbestellung (DirectOrder) * B2B-Funktionen wie Registrierungs- und Freigabeprozesse, Firmenkonten inkl. Berechtigungen etc. * Erweiterte Auftrags- und Fulfillment-Prozesse # Storefront API Basics Source: https://dokumentation.websale.de/schnittstellen/storefront-api/storefront-api-basics Grundlagen der WEBSALE Storefront API: Basis-URL, Versionierung, JSON-Format, Authentifizierung, Header, Session-Handling und Fehlercodes. Die Seite Storefront API Basics beschreibt die grundlegenden technischen Rahmenbedingungen für die Nutzung der Storefront API. Dazu gehören u. a. Basis-URL und Versionierung, Request-/Response-Format (JSON), Authentifizierung sowie allgemeine Konventionen wie Header, Fehlercodes und Paging. *** ## Basis URL Alle Storefront API-Endpunkte werden unter folgender URL aufgerufen: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://.de/api/v1/ ``` Diese URL ist die Basis für sämtliche Anfragen, z.B. ```http theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/config/address_lists ``` ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/watchList/list ``` ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/form/send ``` Als `ihr-shop.de` muss die Domain des WEBSALE Servers verwendet werden. Diese unterscheidet sich von der Hauptdomain des Shops. Bitte klären Sie die Domain mit Ihrem WEBSALE-Ansprechpartner und beachten Sie auch [Einrichtung der Storefront-API-basierten Storefront](#einrichtung-der-storefront-api-basierten-storefront). Die Endpunktpfade sind fest. Ressourcen-IDs werden nicht als Pfadsegment, sondern als Query-Parameter oder im Request-Body übergeben. ## Authentifizierung Im Gegensatz zur [Admin Interface API](/schnittstellen/admin-interface-api) erfordert die Storefront API keine separate API-Authentifizierung. Anfragen an die Storefront API laufen immer im Kontext des öffentlichen Shops. Einzelne Endpunkte können dennoch eine aktive Session voraussetzen, beispielsweise für Funktionen rund um das Kundenkonto. In diesen Fällen wird der Zugriff nicht über einen separaten API-Login, sondern über die vorhandene [Session](#session-handling) bzw. den normalen Login im Frontend gesteuert. ## Session-Handling Für zusammenhängende Aktionen im Shop (z. B. Warenkorb aufbauen, Merkliste verwenden, kundenabhängige Daten lesen) muss eine Session verwendet werden. Die Session ist die eindeutige ID, mit der der Shop mehrere Requests einem gemeinsamen Kontext zuordnet und damit benutzerspezifische Daten wiedererkennen kann (z. B. Warenkorb-Inhalt und Kundenzuordnung). Nicht alle Endpunkte erfordern eine aktive Session. Das Mitsenden einer Session ist jedoch jederzeit erlaubt und ausdrücklich empfohlen, wenn mehrere Anfragen zu einem zusammenhängenden Nutzungskontext gehören. ### Session erstellen Eine neue Session wird über folgenden Endpunkt erstellt: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/session/create ``` Die genaue Struktur der Response ist in der [Endpunktdokumentation](/schnittstellen/storefront-api/storefront-api-session-handling) beschrieben. Wesentlich ist, dass die Antwort eine Session-ID zurückliefert (z. B. als Feld wie `sessionId` oder ähnlich), die für weitere Requests wiederverwendet wird. ### Session in Requests übergeben Damit der Shop eine bestehende Session erkennt, wird die Session-ID dann bei allen weiteren Anfragen im HTTP-Header `X-Session` mitgesendet. #### **Beispiel-Request (Rohformat)** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET /api/v1/urls/identify?url=/meine-kategorie HTTP/1.1 Host: .de X-Session: 0123456789abcdef ``` #### **Beispiel mit** `curl` ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} curl -X GET "https://.de/api/v1/urls/identify?url=/meine-kategorie" \ -H "X-Session: 0123456789abcdef" ``` * `X-Session` ist der Name des Custom-Headers. * Der Header-Wert ist die zuvor erzeugte Session-ID. Die Session wird niemals über Query-Parameter an die URL angehängt (z. B. `?session=…`), sondern ausschließlich über den Header übertragen. Auf diese Weise bleibt die Session-ID aus URLs und Browser-Historien heraus und kann sauber über den Request-Kontext gesteuert werden. ### Auswirkungen der Session Ob eine Session benötigt oder ausgewertet wird, hängt vom jeweiligen Endpunkt ab: * Für rein öffentliche Daten (z. B. allgemeine Produktinformationen) kann ein Request ohne Session möglich sein. * Wird eine gültige Session mitgesendet, können Endpunkte benutzerspezifische Informationen zurückgeben, z. B.: * kundenabhängige Preise, * bereits gefüllte Warenkörbe, * kundenkontoabhängige Einstellungen. Wird ein Endpunkt aufgerufen, der eine gültige Session oder ein angemeldetes Kundenkonto voraussetzt, antwortet die API bei fehlender oder ungültiger Session mit `400 Bad Request` und dem Fehlerobjekt `{ "error": "badRequest", "detail": "Bad request" }`. Die Statuscodes `401` und `403` werden von der Storefront API nicht verwendet. Die genaue Fehlerbehandlung ist in Abschnitt „[Fehlerbehandlung](#fehlerbehandlung)“ beschrieben. ## Fehlerbehandlung Bei der Storefront API werden Fehler einheitlich über HTTP-Statuscodes und eine strukturierte Fehlerantwort im JSON-Format zurückgegeben. * Der HTTP-Statuscode zeigt an, ob eine Anfrage grundsätzlich erfolgreich war (2xx) oder fehlgeschlagen ist (4xx/5xx). * Die Fehlerantwort im JSON-Format liefert zusätzliche Details, mit denen Fehler im Frontend gezielt ausgewertet und angezeigt werden können (z. B. fehlerhafte Parameter oder fachliche Fehler bei der Ausführung). Die in diesem Abschnitt beschriebene Struktur der Fehlerantwort gilt für alle Storefront-API-Endpunkte. Unter den einzelnen Endpunkten werden nur noch die jeweils spezifischen fachlichen Fehlercodes dokumentiert. ### HTTP-Statuscodes Die Storefront API verwendet die üblichen HTTP-Statuscodes. Typische Beispiele: * **2xx: Erfolg** * `200 OK`: Anfrage erfolgreich, Antwort enthält Daten. Auch anlegende Aufrufe (POST) antworten mit 200. * **4xx: Fehler auf Client-Seite** * `400 Bad Request`: Anfrage ungültig, etwa durch fehlerhafte oder fehlende Parameter (`invalidParameters`), eine fehlende Session bzw. einen fehlenden Login (`badRequest`) oder eine fachlich fehlgeschlagene Aktion (`actionFailed`). * `404 Not Found`: Endpunkt existiert nicht oder wurde mit einer nicht erlaubten HTTP-Methode aufgerufen. * **5xx: Fehler auf Server-Seite** * `500 Internal Server Error`: unerwarteter Fehler im Backend. Bei allen 4xx- und 5xx-Antworten stellt die Storefront API zusätzlich ein Fehlerobjekt im JSON-Format bereit (siehe [Fehler-Response](#fehlerbehandlung)). ### Fehler-Response Alle Fehlermeldungen werden im JSON-Format zurückgegeben. Die Antwort folgt einer einheitlichen Struktur, die es ermöglicht, Fehler systematisch auszuwerten und im Frontend aufzubereiten: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "error": "", "detail": "", "paramErrors": { "": { "type": "" } }, "actionErrors": [ { "code" : "", "details" : {}, "field" : "", "subCode" : "", "text" : "" } ] } ``` Die Felder `paramErrors` und `actionErrors` sind optional: Sie sind nur dann Teil der Antwort, wenn tatsächlich Fehler dieser Art vorliegen. Enthält eine Antwort keine Parameterfehler, fehlt der Schlüssel `paramErrors` ganz (er ist nicht leer, sondern nicht vorhanden). Prüfen Sie deshalb auf Existenz, nicht auf Länge. #### Parameterübersicht Fehler-Response | **Parameter** | **Typ** | **Beschreibung** | | -------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `error` | | Kurzer, technischer Fehlercode auf oberster Ebene. Es gibt genau drei Werte: `invalidParameters` (formal ungültige Parameter, `detail: "Invalid parameters sent"`), `actionFailed` (fachlich fehlgeschlagene Aktion, `detail: "Action Failed"`) und `badRequest` (fehlende oder ungültige Session bzw. fehlender Login, `detail: "Bad request"`). | | `detail` | | Optionale Kurzbeschreibung des Fehlers, z. B. zur Protokollierung oder für technische Auswertungen. | | `paramErrors` | | Objekt mit Detailinformationen zu fehlerhaften Parametern. Die Schlüssel entsprechen den Parameternamen, die Werte sind Objekte mit weiterführenden Angaben zum jeweiligen Fehler. Das Feld entfällt, wenn keine Fehler dieser Art vorliegen. Siehe Abschnitt [Parameter-Fehler-Codes](#parameter-fehler-codes-paramerrors) | | `actionErrors` | | Liste fachlicher Fehler, die bei der Ausführung der eigentlichen Aktion aufgetreten sind (beispielsweise „Bewertung für diese Bestellung nicht zulässig“). Jeder Eintrag enthält u. a.: - `code`: technischer Fehlercode, der die Ursache bezeichnet, - `field`: optional das betroffene Feld, - `text`: sprechende Fehlermeldung zur Anzeige im Frontend, - `details` / `subCode`: optionale Zusatzinformationen. Das Feld entfällt, wenn keine Fehler dieser Art vorliegen. Siehe Abschnitt [Aktionsfehler](#aktionsfehler-actionerrors) | #### Parameter-Fehler-Codes (`paramErrors`) Parameterfehler treten auf, wenn eine Anfrage formal ungültig ist, z. B. weil ein Pflichtfeld fehlt oder ein Wert das falsche Format besitzt. In diesen Fällen gibt die API in der Regel: * den HTTP-Status `400 Bad Request` * das Fehlerobjekt mit * `error = "invalidParameters"` * einem oder mehreren Einträgen in `paramErrors` Die in `paramErrors..type` verwendeten Fehlercodes haben folgende Bedeutung: | **Error Code** | **Typ** | **Beschreibung** | | -------------------- | ------- | ------------------------------------------------------------------------------------------------------------ | | `unknownDataField` | | Ein unbekanntes Feld wurde gesendet. | | `invalidFormat` | | Der Parameter hat ein ungültiges Format, z. B. String statt Integer oder ein nicht parsebares JSON-Fragment. | | `invalidValue` | | Der Wert des Parameters ist ungültig - z.B. außerhalb des gültigen Bereiches. | | `invalidCombination` | | Zwei oder mehr Parameter schließen sich gegenseitig aus. | | `syntaxError` | | Es besteht ein Syntaxfehler im Parameter. | | `missing` | | Ein Pflichtfeld fehlt. | | `readonlyField` | | Es wurde versucht, ein Read-Only-Feld zu beschreiben. | | `duplicateEntry` | | Ein Wert, der nur einmal vorkommen darf, wurde mehrfach verwendet. | #### Aktionsfehler (`actionErrors`) Als „Action“ werden alle API-Aufrufe bezeichnet, die den “Shop-Zustand” ändern – also in der Regel POST-, PUT- oder DELETE-Aufrufe (z. B. Produkt in den Warenkorb legen, Adresse anlegen, Newsletter abonnieren etc.). Reine Lese-Aufrufe (z. B. Produkte laden) sind keine “Actions” und liefern diese Fehler in der Regel nicht. Aktionsfehler treten dann auf, wenn die Anfrage zwar formal korrekt ist (alle Parameter sind gültig), die angeforderte Aktion aber trotzdem nicht erfolgreich durchgeführt werden kann, z.B. * Für eine Bestellung darf keine weitere Bewertung erstellt werden * Das angegebene Produkt ist in diesem Kontext nicht bewertbar * Eine Aktion ist für den aktuellen Zustand nicht erlaubt (z. B. Artikel nicht mehr verfügbar, Mindestmenge nicht erfüllt) In diesen Fällen wird ein geeigneter HTTP-Statuscode (in der Regel ein [4xx-Code](#http-statuscodes), häufig `400 Bad Request`) zurückgegeben. Das Fehlerobjekt enthält zudem: * einen passenden Wert im Feld `error`, der die generelle Fehlerkategorie beschreibt, z. B. `actionFailed`, * einen oder mehrere Einträge in `actionErrors`, die den konkreten Aktionsfehler beschreiben * `code` – technischer Fehlercode (z. B. `ratingNotAllowed`, `orderNotFound`, `cartProductNotAvailable`), * `field` – optional das betroffene Feld oder die betroffene Entität (z. B. `productId`, `cart`), * `text` – sprechender Fehlertext, der im Frontend direkt angezeigt oder lokalisiert werden kann, * `details` – optionales Objekt mit Zusatzinformationen (z. B. betroffene IDs, verfügbare Menge), * `subCode` – optionaler Untercode zur feineren Differenzierung. #### **Beispiel** Ein Kunde versucht, ein Produkt in den Warenkorb zu legen. Die Anfrage ist formal korrekt (alle Parameter vorhanden und im richtigen Format), das Produkt ist jedoch nicht mehr verfügbar. HTTP-Antwort → Status: `400 Bad Request` Response-Body: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "error": "actionFailed", "detail": "Product cannot be added to cart.", "actionErrors": [ { "code": "cartProductNotAvailable", "details": { "productId": 12345, "requestedQuantity": 2, "availableQuantity": 0 }, "field": "productId", "subCode": "", "text": "Das ausgewählte Produkt ist derzeit nicht verfügbar und kann nicht in den Warenkorb gelegt werden." } ] } ``` Aus dieser Antwort geht hervor: * Die Anfrage ist formal korrekt (`paramErrors` fehlt, da keine Parameterfehler vorliegen). * Die Aktion (Produkt in den Warenkorb legen) konnte nicht ausgeführt werden (`error = "actionFailed"`). * Der fachliche Grund ist der Action-Fehler mit * `code = "cartProductNotAvailable"`, * einem betroffenen Feld `field = "productId"` und * einem sprechenden Fehlertext in `text`, der direkt im Frontend angezeigt werden kann. Die hier dargestellte Struktur der Fehlerantwort ist für alle Endpunkte gleich. Welche konkreten Action-Fehlercodes (`actionErrors[].code`) bei einem Endpunkt auftreten können, wird jeweils beim zugehörigen Endpunkt dokumentiert. ## Einrichtung der Storefront-API-basierten Storefront Wird ein WEBSALE Shop über seine Domain aufgerufen (z. B. `www.ihr-shop.de`), wird die Storefront standardmäßig über das WEBSALE Template-Theme ausgeliefert und dargestellt. Soll die Storefront stattdessen auf Basis der Storefront API (z. B. mit einem eigenen Frontend-Framework) betrieben werden, sind entsprechende Einstellungen erforderlich, damit diese neue Storefront ausgeliefert und verwendet wird. Bitte sprechen Sie hierzu mit Ihrem WEBSALE Ansprechpartner, um die dafür notwendigen Einstellungen im Detail zu besprechen. # Storefront API Checkout (In Progress) Source: https://dokumentation.websale.de/schnittstellen/storefront-api/storefront-api-checkout-in-progress Checkout-Endpunkte der Storefront API für Versand- und Zahlungsarten, Summenberechnung, Bestellabschluss und Übergang in den Zahlungsfluss. Die Storefront API Checkout stellt Funktionen für den Bestell- und Checkout-Prozess bereit. Darüber werden die Schritte abgedeckt, die typischerweise zwischen Warenkorb und Bestellabschluss stattfinden. Dazu gehören: * Ermitteln und Auswählen von Versandarten * Ermitteln und Auswählen von Zahlungsarten * Berechnung von Gesamtsummen (inklusive Berücksichtigung von Rabatten, Aufschlägen und weiteren preisrelevanten Bestandteilen) * Prüfen und Übernehmen von checkout-relevanten Daten (z. B. Liefer-/Rechnungsdaten, Voraussetzungen und Bedingungen für den Bestellabschluss) * Auslösen des Bestellabschlusses und Übergang in den jeweiligen Zahlungsfluss (je nach Zahlungsart) Darüber hinaus ermöglicht die Schnittstelle den Zugriff auf alle relevanten Einstellungen und Regeln für den Bestellprozess, z. B. Mindestbestellwerte, Mindermengenzuschläge und weitere checkout-relevante Einschränkungen oder Zuschlagslogiken, sodass diese im Frontend korrekt berücksichtigt und angezeigt werden können. Diese Storefront API befindet sich aktuell noch im Aufbau und steht derzeit **nur in einem begrenzten Funktionsumfang** zur Verfügung. Welche Informationen und Endpunkte momentan enthalten sind, ist der unten stehenden Schnittstellenbeschreibung zu entnehmen. Die Weiterentwicklung dieser Schnittstelle wird kontinuierlich fortgesetzt. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | -------------------------- | ----------------------------- | --------------------- | ------------------- | --------------------- | ------------------- | | Checkout-Status abrufen | `checkout/status` | | | | | | Art des Kontos setzen | `checkout/setAccountType` | | | | | | Entwurfsadresse übernehmen | `checkout/commitDraftAddress` | | | | | ## Methoden für den Checkout Folgende Methoden liefern Informationen zum aktuellen Checkout-Prozess der aktiven Session. ### GET checkout/status Der folgende Aufruf liefert die Gesamtkosten für den Checkout-Prozess (einschließlich Mindermengenzuschlag „`surcharge`“, Versand- und Zahlungsartenkosten, Gutscheine etc.). Er kann beispielsweise verwendet werden, um die Gesamtsumme im Checkout zu aktualisieren, ohne die Seite neu zu laden. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/checkout/status ``` #### **Parameterübersicht** #### **Header-Parameter** | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](/schnittstellen/storefront-api/storefront-api-basics#session-handling) | #### **Beispiel-Response** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "currency" : "EUR", "paymentCost" : 0, "shippingCost" : 0, "surchargeCost" : 0, "total" : 14.9, "totalGross" : 14.9, "totalNet" : 12.52, "totalTax" : 2.38, "totalVoucher" : 0, "totalWeight" : 0 } ``` ### POST checkout/commitDraftAddress Übernimmt die zuvor im Checkout hinterlegte Entwurfsadresse als Rechnungs- oder Lieferadresse der aktuellen Session. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/checkout/commitDraftAddress ``` #### **Parameterübersicht** #### **Header-Parameter** | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](/schnittstellen/storefront-api/storefront-api-basics#session-handling) | #### **Body-Parameter** | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `addressType` | string | **Pflichtfeld**
    Legt fest, ob die Entwurfsadresse als Rechnungs- oder Lieferadresse übernommen wird.
    Gültige Werte:
    - `"bill"` - Rechnungsadresse
    - `"shipping"` - Lieferadresse
    Andere Felder im Body werden mit `invalidParameters` abgelehnt. | #### **Antwort (200)** Die Antwort enthält die Felder `selectedPayment`, `selectedShippingMethod`, `sum` und `problems`. Bei fachlichen Fehlern enthält die Antwort zusätzlich das Feld `errors`. ### POST checkout/setAccountType Der folgende Aufruf setzt die Art des Kontos, welches für die Bestellung im Checkout verwendet wird. Damit wird festgelegt, ob der Kunde als Neukunde, Bestandskunde oder Gast bestellt. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/checkout/setAccountType ``` #### **Beispiel-Request** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountType": "guest" } ``` #### **Parameterübersicht** #### **Header-Parameter** | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](/schnittstellen/storefront-api/storefront-api-basics#session-handling) | #### **Body-Parameter** | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `accountType` | string | **Pflichtfeld**
    Art des Kundenkontos.
    Gültige Werte:
    - `“new”` - Neukunde
    - `“registered”` - Registrierter Kunde
    - `“guest”` - Bestellung ohne Registrierung | #### **Fehlercodes** | **Code** | **Beschreibung** | | -------------------- | ---------------------------------------------------------------------------- | | `missingAccountType` | `accountType` wurde nicht oder als leerer String übergeben. | | `invalidAccountType` | `accountType` enthält einen Wert außerhalb von `new`, `registered`, `guest`. | # Storefront API Formulare Source: https://dokumentation.websale.de/schnittstellen/storefront-api/storefront-api-formulare Online-Formulare des Shops über die Storefront API auflisten, einzelne Formulare oder Felder abrufen und ausgefüllte Daten zurück übermitteln. Über den API-Endpunkt für Formulare werden die im Shop verfügbaren Online-Formulare bereitgestellt und deren Felder, Pflichtangaben und Validierungen ausgeliefert. Über den Endpunkt können alle Formulare aufgelistet, ein einzelnes Formular oder Feld abgerufen und ausgefüllte Formulare übermittelt werden. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | ----------------------------------------------- | ------------------ | --------------------- | ------------------- | --------------------- | ------------------- | | Alle Formulare abrufen. | `form/list` | | | | | | Ein bestimmtes Formular abrufen. | `form/get` | | | | | | Ein bestimmtes Formularfeld abrufen. | `form/getField` | | | | | | Eine Formularanfrage versenden. | `form/send` | | | | | | Details einer zuvor gesendeten Anfrage abrufen. | `form/loadInquiry` | | | | | ## Methoden für Formulare Diese Methoden decken den kompletten Lebenszyklus von Online-Formularen im Shop ab. Sie lesen alle konfigurierten Formulare einschließlich der Felder, der Pflichtkennzeichnung, der Validierungen und der E-Mail-Einstellungen aus. Bei Bedarf können ein einzelnes Formular oder ein einzelnes Feld gezielt nach ID geladen werden. Darüber hinaus ist das Übermitteln ausgefüllter Formulare möglich. Dabei wird eine Vorgangs-ID (`inquiryId`) bereitgestellt, die eine spätere Nachverfolgung bzw. Detailabfragen ermöglicht. ### GET form/list Der folgende Aufruf liefert alle im Shop konfigurierten Formulare inklusive Felddefinitionen und E-Mail-Einstellungen. Er kann zum Erstellen von Formularen inklusive Pflichtfeldern und Validierungen genutzt werden. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/form/getAll ``` #### **Parameterübersicht** | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### **Beispiel-Response** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "email": { "fromAddress": "contact@myshop.de", "fromName": "myshop Versender", "merchantEmail": "dev-test@websale.de", "subject": "Ihre Kontaktanfrage wurde aufgenommen.", "template": "contact.htm" }, "fields": [ { "label": "Vorname", "name": "firstName", "required": false, "validations": [ { "name": "minLength", "type": "dataChecker" }, { "name": "maxLength", "type": "dataChecker" } ] }, { "label": "Nachname", "name": "lastName", "required": false, "validations": [ { "name": "minLength", "type": "dataChecker" }, { "name": "maxLength", "type": "dataChecker" } ] }, { "label": "Betreff", "name": "subject", "required": true, "validations": [ { "name": "maxLength", "type": "dataChecker" } ] }, { "label": "Kundennummer", "name": "customerNumber", "required": false, "validations": [ { "name": "maxLength", "type": "dataChecker" } ] }, { "label": "Text", "name": "text", "required": true, "validations": [ { "name": "minLength", "type": "dataChecker" }, { "name": "maxLength", "type": "dataChecker" } ] } ], "name": "contact" }, { "email": { "fromAddress": "contact@myshop.de", "fromName": "myshop Versender", "merchantEmail": "dev-test@websale.de", "subject": "Ihre Kontaktanfrage wurde aufgenommen.", "template": "contact.htm" }, "fields": [ { "label": "Vorname", "name": "firstName", "required": false, "validations": [ { "name": "minLength", "type": "dataChecker" }, { "name": "maxLength", "type": "dataChecker" } ] }, { "label": "Nachname", "name": "lastName", "required": false, "validations": [ { "name": "minLength", "type": "dataChecker" }, { "name": "maxLength", "type": "dataChecker" } ] }, { "label": "Betreff", "name": "subject", "required": true, "validations": [ { "name": "maxLength", "type": "dataChecker" } ] }, { "label": "Kundennummer", "name": "customerNumber", "required": false, "validations": [ { "name": "maxLength", "type": "dataChecker" } ] }, { "label": "Text", "name": "text", "required": true, "validations": [ { "name": "minLength", "type": "dataChecker" }, { "name": "maxLength", "type": "dataChecker" } ] } ], "name": "contact_friendlycaptcha" } ] ``` ### GET form/get Mit folgendem Aufruf kann ein einzelnes Formular anhand seiner technischen ID (abrufbar über „form/getAll”) inklusive Felddefinitionen, Pflichtangaben, Validierungen und E-Mail-Einstellungen geladen werden. Er kann zum gezielten Anzeigen eines Formulars verwendet werden. Beispiel-Aufruf, der ein Formular mit der `formId` `contact` lädt: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/form/get?formId=contact ``` #### **Parameterübersicht** | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------ | | `formId` | string | **Pflichtfeld**
    Technische ID des Formulars (abrufbar über `form/getAll`) | #### **Beispiel-Response** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": { "fromAddress": "contact@myshop.de", "fromName": "myshop Versender", "merchantEmail": "dev-test@websale.de", "subject": "Ihre Kontaktanfrage wurde aufgenommen.", "template": "contact.htm" }, "fields": [ { "label": "Vorname", "name": "firstName", "required": false, "validations": [ { "name": "minLength", "type": "dataChecker" }, { "name": "maxLength", "type": "dataChecker" } ] }, { "label": "Nachname", "name": "lastName", "required": false, "validations": [ { "name": "minLength", "type": "dataChecker" }, { "name": "maxLength", "type": "dataChecker" } ] }, { "label": "Betreff", "name": "subject", "required": true, "validations": [ { "name": "maxLength", "type": "dataChecker" } ] }, { "label": "Kundennummer", "name": "customerNumber", "required": false, "validations": [ { "name": "maxLength", "type": "dataChecker" } ] }, { "label": "Text", "name": "text", "required": true, "validations": [ { "name": "minLength", "type": "dataChecker" }, { "name": "maxLength", "type": "dataChecker" } ] } ], "name": "contact" } ``` ### GET form/getField Mit dem folgenden Aufruf wird ein Formularfeld mit Label, Pflichtstatus und Validierungen geladen. Er kann verwendet werden, um das Feld gezielt anzuzeigen, ohne das ganze Formular neu zu laden. Beispiel-Aufruf, der das Feld `firstName` aus dem Formular `contact` lädt: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/form/getField?formId=contact&fieldId=firstName ``` #### **Parameterübersicht** | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------ | | `formId` | string | **Pflichtfeld**
    Technische ID des Formulars (abrufbar über `form/getAll`) | | `fieldId` | string | **Pflichtfeld**
    ID/Name des Feldes im Formular (z.B. `firstName`) | #### **Beispiel-Response** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "label": "Vorname", "name": "firstName", "required": false, "validations": [ { "name": "minLength", "type": "dataChecker" }, { "name": "maxLength", "type": "dataChecker" } ] } ``` ### GET form/loadInquiry Mit folgendem Aufruf kann eine bereits versendete Anfrage anhand ihrer Vorgangs-ID geladen werden. Er kann verwendet werden, um nach dem Absenden des Formulars eine Bestätigungsseite anzuzeigen oder um eine Anfrage später erneut anzusehen. Beispiel-Aufruf, der die Anfrage mit der ID `7930f7e9fa7bb07b` lädt: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/form/loadInquiry?inquiryId=7930f7e9fa7bb07b ``` #### **Parameterübersicht** | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------------------------------------------------------------------------- | | `inquiryId` | string | **Pflichtfeld**
    Vorgangs-ID der Anfrage (erhältlich z.B. aus dem Response von `form/send`) |   #### **Beispiel-Response** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "createdAt": "2025-11-11T14:36:03Z", "form": { "customerNumber": { "label": "Kundennummer", "value": "" }, "firstName": { "label": "Vorname", "value": "Eren" }, "lastName": { "label": "Nachname", "value": "Jäger" }, "subject": { "label": "Betreff", "value": "Wichtige Mitteilung" }, "text": { "label": "Text", "value": "tatakae!" } }, "formId": "contact", "id": "7930f7e9fa7bb07b", "submitter": { "email": "test@example.de", "ipAddress": "172.18.0.XXX", "sessionId": "4d1536fe...cd07d" } } ``` ### POST form/send Mit folgendem Aufruf wird eine Formularanfrage (z. B. ein Kontaktformular) an den Shop gesendet und dafür ein Vorgang erzeugt. Er ist zum Absenden eines Formulars und zum Anzeigen einer Bestätigung inklusive Vorgangsnummer verwendbar. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/form/send ``` #### **Beispiel-Request** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "formId": "contact", "email": "test@example.de", "form": { "firstName": "Eren", "lastName": "Jäger", "subject": "Wichtige Mitteilung", "text": "tatakae!" } } ``` #### **Parameterübersicht** | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `formId` | string | **Pflichtfeld**
    Technische ID des Formulars (abrufbar über `form/getAll`) | | `email` | string | **Pflichtfeld**
    Absender-/Antwort-E-Mail-Adresse der anfragenden Person. | | `form` | object | **Pflichtfeld**
    Hier werden die Feld-IDs aus der Formular-Definition (z.B. `firstName`, `subject`, `text`) inklusive ihres Wertes (Vorname, Betreff etc.) angegeben. | #### **Beispiel-Response** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "inquiryId": "7930f7e9fa7bb07b" } ``` `InquiryId` ist die Vorgangs-ID der gesendeten Anfrage. #### **Fehlercodes** | **Code** | **Beschreibung** | | --------------------- | ------------------------------------------------------------------------------------- | | `captchaFailed` | Für das Formular ist ein Captcha konfiguriert und das mitgegebene Captcha ist falsch. | | `invalidFormId` | Die angegebene Formular-ID ist ungültig. | | `createInquiryFailed` | Interner Fehler. Bitte wende dich an den WEBSALE-Support. | # Storefront API Gutscheine Source: https://dokumentation.websale.de/schnittstellen/storefront-api/storefront-api-gutscheine Gutscheincodes in der Storefront über die Storefront API prüfen, einlösen und entfernen sowie aktualisierte Warenkorbsummen und Rabatte abrufen. Die Storefront API Gutscheine ermöglicht es, Gutscheincodes in der Storefront einzulösen und zu entfernen. Die API prüft dabei automatisch, ob ein Code gültig ist, und liefert nach der Einlösung die aktualisierten Warenkorbwerte (z. B. Rabatte und Summen) sowie bei Bedarf Hinweise/Fehlermeldungen zurück. *** ## Unterstützte Methoden Angabe aller Unterstützten Methoden | **Befehl** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | ------------------------ | ---------------- | --------------------- | ------------------- | --------------------- | --------------------- | | Gutschein Daten auslesen | `voucher/get` | | | | | | Gutschein einlösen | `voucher/redeem` | | | | | | Gutschein löschen | `voucher/delete` | | | | | ## Fehlerformat Alle Fehler werden mit **HTTP 400** und folgendem Rumpf beantwortet: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "error": "actionFailed", "detail": "Action Failed", "actionErrors": [ { "code": "invalidVoucherId", "subCode": "", "field": "id", "text": "…", "details": {} } ] } ``` * `error` = `invalidParameters` bei Fehlern in Parametern/Feldtypen (Details in `paramErrors`, Schlüssel = Parametername, Wert `{"type": "missing" | "invalidFormat" | "invalidValue" | "unknownField" | …}`). * `error` = `actionFailed` bei fachlichen Fehlern. Die in den folgenden Tabellen genannten Fehlercodes stehen dann in `actionErrors[].code`. * Ein Aufruf mit falscher HTTP-Methode wird mit **HTTP 404** beantwortet (nicht 405). * Fehlt die Session (`x-session`), wird mit **HTTP 400** geantwortet. ## Methoden für Gutscheine Diese Methoden ermöglichen das Prüfen, Einlösen und Entfernen von Gutscheinen direkt im Warenkorb oder im Checkout. ### GET voucher/get Dieser Aufruf liest Stammdaten zu einem Gutscheincode aus (z.B. Wert, Währung, Mindestbestellwert). Diese Informationen können im Warenkorb und Checkout verwendet werden, um einen Gutschein vor dem Einlösen zu prüfen und Infos wie Betrag und Bedingungen anzuzeigen. Beispiel-Aufruf für den Gutschein mit der Gutscheinnummer `7G3M-L2UU-CK1B-A2J2`: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/voucher/get?id=7G3M-L2UU-CK1B-A2J2 ``` #### **Parameterübersicht** #### **Query-Parameter** | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | -------------------------------------------------------------- | | `id` | String | **Pflichtfeld**
    Gutscheincode, der abgefragt werden soll. | #### **Beispiel-Response** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "currency": "EUR", "id": "7G3M-L2UU-CK1B-A2J2", "minOrderValue": 0, "taxId": "19", "value": 10.5 } ``` | Feld | Typ | Beschreibung | | -------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | Gutscheincode. | | `value` | float | Aktuell wirksamer Wert (absoluter Wert plus errechneter Prozentanteil, gedeckelt durch `maxDiscountValue`). Ist der Mindestbestellwert nicht erreicht, ist der Wert 0. | | `currency` | string | Währung des Gutscheins. | | `taxId` | string | Steuerschlüssel des Gutscheins. | | `usedValue` | float | Bereits verbrauchter Wert. Nur vorhanden, wenn gesetzt. | | `minOrderValue` | float | Mindestbestellwert. Nur vorhanden, wenn gesetzt. | | `maxDiscountValue` | float | Maximaler Rabattbetrag bei Prozentgutscheinen. Nur vorhanden, wenn gesetzt. | | `validFrom` / `validUntil` | string (ISO 8601) | Gültigkeitszeitraum. Nur vorhanden, wenn gesetzt. | ### POST voucher/redeem Dieser Aufruf löst einen Gutscheincode für den aktuellen Warenkorb ein und liefert Informationen zum eingelösten Gutschein und zum verbleibenden Wert. Dieser Befehl kann verwendet werden, um im Warenkorb oder Checkout den Gutschein zu verrechnen oder den eingelösten Betrag und ggf. den Restwert anzuzeigen. Beispiel-Aufruf für die Einlösung des Gutscheins `7G3M-L2UU-CK1B-A2J2`: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/voucher/redeem ``` #### **Beispiel-Request** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "7G3M-L2UU-CK1B-A2J2" } ``` #### **Parameterübersicht** #### **Header-Parameter** | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](/schnittstellen/storefront-api/storefront-api-basics) | #### **Body-Parameter** | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------- | | `id` | string | **Pflichtfeld**
    Gutscheincode, der einzulösen ist. | #### **Beispiel-Response** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "info": { "totalUsedValue": 0, "totalValue": 10.5, "vouchers": [ { "currency": "EUR", "id": "7G3M-L2UU-CK1B-A2J2", "taxId": "19", "usedValue": 0, "value": 10.5 } ] } } ``` **Wirkungslose Gutscheine** `voucher/redeem` prüft nur die Gültigkeit des Codes, nicht seine Wirkung auf den aktuellen Warenkorb. Ein Gutschein kann ohne Fehler eingelöst werden und trotzdem 0,00 Rabatt ergeben. Prüfen Sie deshalb nach dem Einlösen `ineffectiveVoucherErrors` und `isOrderBlockedByIneffectiveVoucher` aus den Checkout-Daten. | Code | Bedeutung | | ------------------------- | ------------------------------------------------------------ | | `noValidProducts` | Im Warenkorb liegt kein Produkt, für das der Gutschein gilt. | | `minOrderValueNotReached` | Der Mindestbestellwert des Gutscheins ist nicht erreicht. | Jeder Eintrag hat die Felder `code`, `subCode` (immer leer), `field` (immer leer), `text` (übersetzter Meldungstext) und `details.voucherId` (fehlt, wenn sich der Fehler auf die Summe mehrerer Gutscheine bezieht). Ist `isOrderBlockedByIneffectiveVoucher` = `true`, lehnt der Shop die Bestellbestätigung mit dem Fehlercode `voucherIneffective` ab. #### **Fehlercodes** | **Fehlercode** | **Beschreibung** | | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `invalidVoucherId` | Die angegebene ID ist kein gültiger Gutscheincode. | | `deactivated` | Der Gutschein wurde deaktiviert. | | `expired` | Der Gutschein ist abgelaufen. | | `notYetValid` | Der Gutschein ist noch nicht gültig. | | `maxCountExceeded` | Die maximale Anzahl an Gutscheinen pro Bestellung wurde erreicht. Die Obergrenze wird pro Shop konfiguriert. Der Standardwert ist **1**. Der aktuell geltende Wert steht im Feld `maximumCount` der Gutscheinübersicht. | | `valueSpent` | Der Gesamtwert des Gutscheins ist bereits verbraucht. | | `currencyMismatch` | Die Gutscheinwährung passt nicht zur Shop-Währung. | | `invalidCustomer` | Der Gutschein darf von diesem Kunden nicht eingelöst werden. | | `invalidSubshop` | Der Gutschein darf in diesem Subshop nicht eingelöst werden. | | `missingId` | Es wurde kein Gutscheincode übergeben. | | `duplicateId` | Dieser Gutscheincode ist bereits im Warenkorb eingelöst. | | `expressCheckoutNotAllowed` | Ein Express-Checkout ist aktiv - Gutscheine dürfen derzeit nicht geändert werden. | | `insuffientAmount` | Der verfügbare Gutscheinwert reicht nicht aus. (Schreibweise wie im Code, mit fehlendem „ic“.) | | `repoUpdateFailed` | Der Gutschein konnte technisch nicht aktualisiert werden. | | `invalidVoucherConfiguration` | Der Gutschein ist fehlerhaft konfiguriert (kein Typ hinterlegt). | ### DELETE voucher/delete Dieser Aufruf entfernt einen eingelösten Gutscheincode aus dem aktuellen Warenkorb und aktualisiert die Gutscheinübersicht. Dieser Befehl kann verwendet werden, um im Warenkorb oder Checkout eine versehentlich eingelöste oder nicht gewünschte Gutscheinanwendung rückgängig zu machen. Beispiel-Aufruf für das Entfernen des Gutscheins mit dem Code `7G3M-L2UU-CK1B-A2J2`: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} DELETE https://.de/api/v1/voucher/delete ``` #### **Beispiel-Request** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "7G3M-L2UU-CK1B-A2J2" } ``` #### **Parameterübersicht** #### **Header-Parameter** | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](/schnittstellen/storefront-api/storefront-api-basics) | #### **Body-Parameter** | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------- | | `id` | String | **Pflichtfeld**
    Gutscheincode, der entfernt werden soll. | #### **Beispiel-Response** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "info": { "totalUsedValue": 0, "totalValue": 0, "vouchers": [] } } ``` #### **Fehlercodes** | **Fehlercode** | **Beschreibung** | | --------------------------- | ---------------------------------------------------------------------------------- | | `invalidVoucherId` | Die angegebene ID ist kein gültiger Gutscheincode. | | `expressCheckoutNotAllowed` | Ein Express-Checkout ist aktiv - der Gutschein darf derzeit nicht entfernt werden. | # Storefront API Katalog Source: https://dokumentation.websale.de/schnittstellen/storefront-api/storefront-api-katalog Produkt- und Kategoriedaten für die Storefront über die Katalog API abrufen, inklusive Attribute, Kategoriestruktur, SEO-Meta-Daten und URLs. Die Katalog API stellt die zentralen Informationen für Produkte und Kategorien bereit und bildet damit die Grundlage für Produktdetailseiten, Kategorieseiten und Navigationselemente. Sie liefert Standardattribute (z. B. Name, Beschreibung, Preis), ergänzt um individuelle Produkt- und Kategorieattribute sowie SEO-Informationen wie Meta-Daten und sprechende URLs. Zusätzlich können Kategoriestrukturen (Hierarchien, Unterkategorien, Verknüpfungen) abgerufen werden, ebenso einzelne Produkte/Kategorien oder Produktlisten im Kontext einer Kategorie. Funktionen für Suchergebnisse und Kategorieseiten – etwa Filter, Sortierung, Paging oder die Anzahl der Produkte pro Seite – werden nicht über die Katalog API bereitgestellt. Diese Aufgaben übernimmt das separate Modul **WEBSALE search** und die Einbindung kann entweder über die entsprechenden [WEBSALE WebComponents](/frontend/referenz/components) oder die [Search API](/schnittstellen/search-api) erfolgen. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | --------------------------------------------------------------- | ----------------------------------------- | --------------------- | ------------------- | ------------------- | ------------------- | | Produktdetails zu einem Artikel abrufen | `catalog/product/load` | | | | | | Produktdetails zu mehreren Artikeln abrufen | `catalog/product/loadList` | | | | | | Varinanten-Informationen zu einem Produkt abrufen | `catalog/product/variantInfo` | | | | | | Alle Kategorien laden, in denen ein bestimmtes Produkt vorkommt | `catalog/product/categoryMembership` | | | | | | Kategoriepfade laden, in denen ein bestimmtes Produkt vorkommt | `catalog/product/categoryMembershipPaths` | | | | | | Liste aller verfügbaren Produktfelder laden | `catalog/product/fields` | | | | | | Liste aller verfügbaren benutzerdefinierten Produktfelder laden | `catalog/product/customFields` | | | | | | Details einer Kategorie laden | `catalog/category/load` | | | | | | Unterkategorie einer Kategorie laden | `catalog/category/loadChildren` | | | | | | Kompletten Pfad bis zur Kategorie laden | `catalog/category/path` | | | | | | Produktliste für eine angegebene Kategorie laden | `catalog/category/products` | | | | | | Liste aller verfügbaren Kategoriefelder laden | `catalog/category/fields` | | | | | | Liste aller benutzerdefinierten Kategoriefelder laden | `catalog/category/customFields` | | | | | *** ## Methoden für Produkte Mithilfe dieser Methoden werden Produktinformationen für die Storefront bereitgestellt. Dabei werden die Detaildaten eines einzelnen Artikels (inklusive konfigurierbarer Produktfelder und ggf. Custom-Felder) geladen und ergänzend Varianteninformationen (z. B. auswählbare Attribute und zugehörige Variantenartikel) geliefert. Darüber hinaus können alle Kategorien und Kategoriepfade ermittelt werden, in denen ein Produkt geführt wird, beispielsweise für Breadcrumbs, Kachel-Teaser oder Filter. Über eigene Endpunkte wird zudem die vollständige Liste aller standardisierten und benutzerdefinierten Produktfelder zurückgegeben. Somit können Suche, Filter, Detailseiten und Integrationen (z. B. ERP-/PIM-Anbindung) dynamisch auf der tatsächlich im Shop konfigurierten Datenstruktur aufbauen. ## GET catalog/product/load Folgender Aufruf lädt die Produktdetails zu einem Artikel: Welche Felder im Response erscheinen, lässt sich in der Katalog-Konfiguration steuern: [storefrontApi - Storefront-API](https://websaleag-44ee7ea6.mintlify.app/konfiguration/storefrontapi-storefront-api#3-storefrontapi-catalogapisettings-steuerung-der-katalog-endpunkte). Dies ist zum Anzeigen einer Produktdetailseite oder zum gezielten Nachladen von Produktinfos verwendbar. Ist die Ausgabe von Produkt- beziehungsweise Kategoriedaten in der Konfiguration abgeschaltet (`enableProductDataEndpoint` beziehungsweise `enableCategoryDataEndpoint`), antwortet der Endpunkt mit HTTP 200 und dem Body `null`. Prüfen Sie den Body deshalb auf `null`, bevor Sie Felder auslesen. Beispiel-Aufruf, der die Produktdetails für das Produkt mit der ID `146-78608` lädt: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/catalog/product/load?productId=146-78608 ``` #### **Parameterübersicht** | **Parameter** | **Typ** | **Beschreibung** | | -------------- | ------- | ---------------------------------------------------------------------------------------------- | | `productId` | string | **Pflichtfeld\***
    Produkt-ID des Artikels. | | `itemNumber` | string | **Pflichtfeld\***
    Produktnummer (SKU) des Artikels. | | `customNumber` | string | **Pflichtfeld\***
    Eine frei vergebene Artikelkennung (z.B. ERP-ID oder Marketing-Nummer). | \*Es muss genau einer der drei Parameter übergeben werden. #### **Beispiel-Response** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "custom": { "image": {}, "setOrgPrice": 0.0 }, "id": "146-78608", "name": "Plushie", "price": 6.7, "setOrgPrice": 0.0 } ``` Benutzerdefinierte Felder liefert der Response gesammelt im Objekt `custom`. Felder vom Typ `MultiFormatImage` (in den Beispielen das Feld `image`) werden als Objekt zurückgegeben. Ein solches Feld speichert ein Bild in mehreren Formaten. Die Formate legen Sie im Admin Interface im Service Bildkonverter fest. Den Typ eines Feldes fragen Sie über [catalog/product/customFields](#get-catalogproductcustomfields) ab. Wie Sie Bildfelder in Frontend-Templates je Format ausgeben, beschreibt [WSProducts: Produktbilder](/frontend/referenz/module/wsproducts#produktbilder). Bild-URLs können Sie außerdem über die [API-Referenz Bildkonverter](/schnittstellen/admin-interface-api/api-referenz-bildkonverter) der Admin Interface API abfragen. ## GET catalog/product/loadList Folgender Aufruf lädt die Produktdetails zu mehreren Artikeln: Welche Felder im Response erscheinen, lässt sich in der Katalog-Konfiguration steuern: [storefrontApi - Storefront-API](https://websaleag-44ee7ea6.mintlify.app/konfiguration/storefrontapi-storefront-api#3-storefrontapi-catalogapisettings-steuerung-der-katalog-endpunkte). Dies ist zum effizienten Anzeigen mehrer Produkte auf einer Kategorieseite verwendbar. Ist die Ausgabe von Produkt- beziehungsweise Kategoriedaten in der Konfiguration abgeschaltet (`enableProductDataEndpoint` beziehungsweise `enableCategoryDataEndpoint`), antwortet der Endpunkt mit HTTP 200 und dem Body `null`. Prüfen Sie den Body deshalb auf `null`, bevor Sie Felder auslesen. Beispiel-Aufruf, der die Produktdetails für die Produkte mit der ID `146-78608` und `147-3720` lädt: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/catalog/product/loadList?productId=146-78608&productId=147-3720 ``` #### **Parameterübersicht** | **Parameter** | **Typ** | **Beschreibung** | | -------------- | ------- | ---------------------------------------------------------------------------------------------- | | `productId` | string | **Pflichtfeld\***
    Produkt-ID des Artikels. | | `itemNumber` | string | **Pflichtfeld\***
    Produktnummer (SKU) des Artikels. | | `customNumber` | string | **Pflichtfeld\***
    Eine frei vergebene Artikelkennung (z.B. ERP-ID oder Marketing-Nummer). | \*Es können nur Parameter eines Typs (`productId`, `itemNumber`, `customNumber`) übergeben werden. Es können beliebig viele Parameter eines Typs angegeben werden. #### **Beispiel-Response** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "custom": { "image": {}, "setOrgPrice": 0.0 }, "id": "146-78608", "name": "Plushie", "price": 6.7, "setOrgPrice": 0.0 }, { "custom": { "image": {}, "setOrgPrice": 0.0 }, "id": "147-3720", "name": "Stift", "price": 3.7, "setOrgPrice": 0.0 } ] ``` ### GET catalog/product/variantInfo Der folgende Aufruf liefert die Varianteninformationen zu einem Produkt. Er kann beispielsweise zum Aufbau des Varianten-Selectors auf der Produktseite verwendet werden. Beispiel-Aufruf, der die Varianteninformationen zum Produkt mit der ID `146-78608` lädt: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/catalog/product/variantInfo?productId=146-78608 ``` #### **Parameterübersicht** | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------ | | `productId` | string | **Pflichtfeld**
    ID des Produktes, dessen Varianten geladen werden sollen. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "numVariants": 2, "variantAttributes": [ { "name": "Arbeitsspeicher", "options": [ { "name": "128 GB", "resolvedVariant": { "base": { "base": null, "custom": { "image": {}, "setOrgPrice": 0.0 }, "id": "146-78608", "name": "Plushie", "price": 6.7, "setOrgPrice": 0.0 }, "custom": { "image": {}, "setOrgPrice": 0.0 }, "id": "146-78608.1", "name": "Plushie", "price": 6.7, "setOrgPrice": 0.0 } }, { "name": "512 GB" } ] } ] } ``` ### GET catalog/product/categoryMembership Mit folgendem Aufruf werden alle Kategorien ausgegeben, in denen ein bestimmtes Produkt aktuell einsortiert ist. Er kann für Breadcrumbs verwendet werden oder dazu, die Produktnavigation/Filter vorzubelegen. Beispiel-Aufruf, der alle Kategorien ausgibt, in denen das Produkt mit der ID `147-15732` einsortiert ist: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/catalog/product/categoryMemberships?productId=147-15732 ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------------------------------------------------------------------- | | `productId` | string | **Pflichtfeld**
    ID des Produktes, dessen Kategoriezugehörigkeiten geladen werden sollen. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "custom": { "image": {} }, "id": "135-98530", "name": "Coole Dinge" }, { "custom": { "image": {} }, "id": "104-40827", "name": "Sale" } ] ``` ### GET catalog/product/categoryMembershipPaths Mit dem folgenden Aufruf werden alle vollständigen Kategoriepfade (von der Wurzel zur Zielkategorie) geliefert, in denen ein bestimmtes Produkt vorkommt. Er kann für Breadcrumbs, die SEO-Navigation oder die Anzeige alternativer Pfade eines Produkts genutzt werden. Beispiel-Aufruf, der die vollständigen Kategoriepfade für das Produkt mit der ID `147-15732` anzeigt: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/catalog/product/categoryMembershipPaths?productId=147-15732 ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------------------------------------------------------------------- | | `productId` | string | **Pflichtfeld**
    ID des Produktes, dessen Kategoriezugehörigkeiten geladen werden sollen. | #### Beispiel-Response Zurückgegeben wird ein Array. Jedes Element ist ein vollständiger Kategoriepfad, also selbst ein Array von Kategorieobjekten von der Wurzel bis zur Zielkategorie. Ist das Produkt in keiner Kategorie einsortiert, ist das äußere Array leer. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ [ { "custom": { "image": {} }, "id": "135-98530", "name": "Coole Dinge" }, { "custom": { "image": {} }, "id": "100-14213", "name": "Bekleidung" } ], [ { "custom": { "image": {} }, "id": "104-40827", "name": "Sale" } ] ] ``` ### GET catalog/product/fields Der folgende Aufruf listet alle im System verfügbaren Standard-Produktfelder inklusive ihrer Metadaten. Er kann zum Aufbau von Produktseiten oder zur Anpassung von Such- und Filterfunktionen verwendet werden. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/catalog/product/fields ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "dataId": "active", "label": "", "manualEditable": true, "name": "active", "nodeId": "content.productField.active", "protectedField": false, "required": false, "searchBoost": 1, "searchable": true, "type": "Enumeration" }, { "dataId": "descr", "label": "", "manualEditable": true, "name": "descr", "nodeId": "content.productField.descr", "protectedField": false, "required": false, "searchBoost": 2, "searchable": true, "type": "Text" }, { "dataId": "id", "label": "", "manualEditable": false, "name": "id", "nodeId": "content.productField.id", "protectedField": false, "required": true, "searchBoost": 2, "searchable": true, "type": "Text" }, { "dataId": "itemNumber", "label": "", "manualEditable": true, "name": "itemNumber", "nodeId": "content.productField.itemNumber", "protectedField": false, "required": true, "searchBoost": 2, "searchable": true, "type": "Text" }, { "dataId": "name", "label": "", "manualEditable": true, "name": "name", "nodeId": "content.productField.name", "protectedField": false, "required": true, "searchBoost": 6, "searchable": true, "type": "Text" }, { "dataId": "price", "label": "", "manualEditable": true, "name": "price", "nodeId": "content.productField.price", "protectedField": false, "required": true, "searchBoost": 1, "searchable": false, "type": "Price" } ] ``` ### GET catalog/product/customFields Der folgende Aufruf listet alle im System verfügbaren benutzerdefinierten Produktfelder inklusive ihrer Metadaten. Er kann zum Aufbau von Produktseiten oder zur Anpassung von Such- und Filterfunktionen verwendet werden. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/catalog/product/customFields ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "dataId": "4682", "label": "activityLevel", "manualEditable": true, "name": "activityLevel", "nodeId": "content.customProductField.activityLevel", "protectedField": false, "required": false, "searchBoost": 1, "searchable": false, "type": "Text" }, { "dataId": "4683", "label": "animalSize", "manualEditable": true, "name": "animalSize", "nodeId": "content.customProductField.animalSize", "protectedField": false, "required": false, "searchBoost": 1, "searchable": false, "type": "Text" }, { "dataId": "4684", "label": "animalSpecies", "manualEditable": true, "name": "animalSpecies", "nodeId": "content.customProductField.animalSpecies", "protectedField": false, "required": false, "searchBoost": 1, "searchable": false, "type": "Text" }, { "dataId": "4685", "label": "areaOfApplication", "manualEditable": true, "name": "areaOfApplication", "nodeId": "content.customProductField.areaOfApplication", "protectedField": false, "required": false, "searchBoost": 1, "searchable": false, "type": "Text" } ] ``` *** ## Methoden für Kategorien Diese Methoden arbeiten mit den Kategorien im Katalog: Sie laden die Detaildaten einer einzelnen Kategorie, geben deren direkte Unterkategorien zurück und liefern den vollständigen Pfad von der Wurzel bis zur Zielkategorie (z. B. für Breadcrumbs). Darüber hinaus können alle Produkte einer Kategorie abgefragt und die im System verfügbaren Kategoriefelder ausgelesen werden. ### GET catalog/category/load Folgender Aufruf lädt die Details einer einzelnen Kategorie (z. B. ID, Name). Er kann zur Anzeige von Kategorietiteln, -bildern/-inhalten sowie für Navigations- oder Breadcrumb-Aufbauten verwendet werden. Beispiel-Aufruf, der die Details zur Kategorie mit der ID `135-98530` anzeigt: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/catalog/category/load?categoryId=135-98530 ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------------------------------------- | | `categoryId` | string | **Pflichtfeld**
    ID der Kategorie, die geladen werden soll. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "custom": { "image": {} }, "id": "135-98530", "name": "Coole Dinge" } ``` ### GET catalog/category/loadChildren Mit folgendem Aufruf werden die direkten Unterkategorien einer Kategorie zurückgegeben. Er kann zum Aufbau von Navigationsbäumen, Kachel- oder Teaser-Listen auf Kategorieseiten sowie für Breadcrumb-Erweiterungen verwendet werden. Beispiel-Aufruf, der die direkten Unterkategorien der Kategorie mit der ID `135-98530` zurückgibt: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/catalog/category/loadChildren?categoryId=135-98530 ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------------------------------------- | | `categoryId` | string | **Pflichtfeld**
    ID der Kategorie, die geladen werden soll. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "custom": { "image": {} }, "id": "100-14213", "name": "Bekleidung" } ] ``` ### GET catalog/category/path Der folgende Aufruf liefert den vollständigen Kategoriepfad von der Wurzel bis zur angegebenen Kategorie (inklusive dieser). Er ist verwendbar für Breadcrumbs, SEO-Pfadangaben, Navigationsleisten oder Kontextanzeigen auf Kategorieseiten. Beispiel-Aufruf, der den vollständigen Pfad der Kategorie mit der ID `104-40827` ausliefert: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/catalog/category/path?categoryId=104-40827 ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ---------------------------------------------------------------------- | | `categoryId` | string | **Pflichtfeld**
    ID der Kategorie, deren Pfad geladen werden soll. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "custom": { "image": {} }, "id": "135-98530", "name": "Coole Dinge" }, { "custom": { "image": {} }, "id": "100-14213", "name": "Bekleidung" }, { "custom": { "image": {} }, "id": "104-40827", "name": "Sale" } ] ``` ### GET catalog/category/products Mit dem folgenden Aufruf wird die Produktliste für eine angegebene Kategorie geliefert. Er kann beispielsweise verwendet werden, um Kategorie-Listingseiten zu befüllen. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/catalog/category/products?categoryId=135-98530 ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ---------------------------------------------------------------------------- | | `categoryId` | string | **Pflichtfeld**
    ID der Kategorie, deren Produkte geladen werden sollen. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "custom": { "image": {}, "setOrgPrice": 0.0 }, "id": "146-78608", "name": "Plushie", "price": 6.7, "setOrgPrice": 0.0 }, { "custom": { "image": {}, "setOrgPrice": 0.0 }, "id": "147-3720", "name": "Stift", "price": 3.7, "setOrgPrice": 0.0 } ] ``` ### GET catalog/category/fields Der folgende Aufruf liefert eine Liste aller verfügbaren Kategoriefelder inklusive Typ-Informationen. Er kann für Formulare, Validierungen oder zur Anzeige von Kategorieattributen verwendet werden. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/catalog/category/fields ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "dataId": "active", "label": "", "manualEditable": true, "name": "active", "required": false, "searchable": false, "type": "Enumeration" }, { "dataId": "descr", "label": "", "manualEditable": true, "name": "descr", "required": false, "searchable": false, "type": "Text" }, { "dataId": "hidden", "label": "", "manualEditable": true, "name": "hidden", "required": false, "searchable": false, "type": "Bool" }, { "dataId": "id", "label": "", "manualEditable": false, "name": "id", "required": true, "searchable": false, "type": "Text" } ] ``` ### GET catalog/category/customFields Der folgende Aufruf liefert eine Liste aller verfügbaren benutzerdefinierten Kategoriefelder inklusive Typ-Informationen. Er kann für Formulare, Validierungen oder zur Anzeige von Kategorieattributen verwendet werden. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/catalog/category/customFields ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "dataId": "4645", "label": "alternatives Template", "manualEditable": true, "name": "alternativeTemplate", "required": false, "searchable": false, "type": "Text" }, { "dataId": "4651", "label": "Default Sortierung", "manualEditable": true, "name": "defaultSort", "required": false, "searchable": false, "type": "Text" }, { "dataId": "4641", "label": "Kategorie", "manualEditable": true, "name": "image", "required": false, "searchable": false, "type": "MultiFormatImage" }, { "dataId": "4644", "label": "Produkte an übergeordnete Kategorien vererben", "manualEditable": false, "name": "inheritProductsToParents", "required": false, "searchable": false, "type": "Bool" } ] ``` # Storefront API Konfigurationen Source: https://dokumentation.websale.de/schnittstellen/storefront-api/storefront-api-konfigurationen Plattform- und subshopspezifische Einstellungen wie Länder, Sprache, Währung und Steuerkontext über die Konfigurations-Storefront-API abrufen. Die Konfiguration API liefert plattform- und subshopspezifische Einstellungen, die für Darstellung und Verhalten der Storefront relevant sind. Typische Inhalte sind globale Shop-Einstellungen (z. B. ShopID, Länderlisten, Anreden), Subshop-spezifische Werte (z. B. Sprache, Währung, Preisformatierung) sowie steuerrelevante Parameter wie Brutto-/Nettoanzeige oder Mehrwertsteuerkontext. Eine vollständige Übersicht aller verfügbaren Konfigurationseinstellungen der Shopplattform ist in der Dokumentation [Konfiguration](/konfiguration) beschrieben. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | ---------------------------------------------- | ------------------------ | --------------------- | ------------------- | ------------------- | ------------------- | | Konfigurierte Adresslisten abfragen | `config/addressLists` | | | | | | Konfigurierte Einwilligungsgruppen abfragen | `config/consent` | | | | | | Konfigurierte Länder + ISO-Codes abfragen | `config/countries` | | | | | | Konfigurierte Shop-Währungen abfragen | `config/currency` | | | | | | Konfiguration für Direktbestellungen abfragen | `config/directOrder` | | | | | | Konfigurierte Inserts (Textbausteine) abfragen | `config/inserts` | | | | | | Aktive Passwortregeln des Shops abfragen | `config/password` | | | | | | Verfügbare Zahlungsarten abfragen | `config/paymentMethods` | | | | | | Konfigurierte Anreden abfragen | `config/salutation` | | | | | | Verfügbare Versandarten abfragen | `config/shippingMethods` | | | | | | Konfigurierte Titel für Kunden abfragen | `config/title` | | | | | | Die aktuelle Subshop-ID abfragen | `subshop/current` | | | | | | Verfügbare Subshops abfragen | `subshop/list` | | | | | | Vollständige Subshop-URL abfragen | `subshop/url` | | | | | ## Methoden für die Konfiguration Mithilfe dieser Methoden können zentrale Shop-Konfigurationen für die Storefront bereitgestellt werden. Sie liefern alle Auswahllisten und Stammdaten, die zum Aufbau von Formularen und Prozessen benötigt werden, darunter vordefinierte Auswahlfelder für Rechnungs- und Lieferadressen, Länder, Währungen, Anreden und Titel. Zudem können checkoutspezifische Einstellungen wie verfügbare Zahlungs- und Versandarten, Direktbestellparameter (Schnelleingabe per Artikelnummer) sowie Passwortregeln (Längenbeschränkungen, zusätzliche Prüfungen) ausgelesen und direkt in der UI berücksichtigt werden. Über die Consent-Konfiguration lassen sich Einwilligungsgruppen und -dienste (z. B. Captcha, Tracking, Medien, Service-E-Mails) samt aktuellem Zustimmungsstatus einsehen. Damit können Consent-Dialoge, Datenschutzeinstellungen und das Nachladen externer Dienste gesteuert werden. ### GET config/addressLists Der folgende Aufruf liefert die konfigurierten Auswahlfelder für Rechnungs- und Lieferadressen. Außerdem ist darin vermerkt, welcher Wert standardmäßig vorausgewählt ist. Die Konfiguration erfolgt unter `general.addressListElements`. Kann zum Aufbau der Adressformulare (Dropdowns/Radiobuttons inkl. Voreinstellung) bei Konto, Checkout und Adressverwaltung verwendet werden. Beispiel-Aufruf, der alle konfigurierten Auswahlfelder zurückliefert: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/config/address_lists ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "bill": { "companyType": { "nodeId": "general.addressListElements:companyType", "defaultValue": "1", "values": [ { "name": "Privat", "value": "1" }, { "name": "Firma", "value": "2" } ] } }, "delivery": { "addressType": { "nodeId": "general.addressListElements:addressType", "defaultValue": "1", "values": [ { "name": "Privat", "value": "1" }, { "name": "Packstation", "value": "3" } ] } } } ``` Jedes Element enthält zusätzlich `nodeId`, die interne Kennung des Konfigurationsknotens. Neben `bill` und `delivery` kann die Antwort weitere Auswahlfelder auf oberster Ebene enthalten, nämlich solche, die keinem Adresstyp zugeordnet sind. Auswahlfelder mit dem Adresstyp *beide* erscheinen sowohl unter `bill` als auch unter `delivery`. ### GET config/consent Der folgende Aufruf liefert die im Shop definierten Einwilligungsgruppen (z. B. Captcha) samt der darin enthaltenen Dienste (z. B. Google reCAPTCHA). Jede Gruppe und jeder Dienst haben unter anderem ein Label, eine interne Kennung, eine Beschreibung sowie den aktuellen Zustimmungsstatus. Er kann verwendet werden, um den Consent-Dialog und die Datenschutzeinstellungen aufzubauen, Gruppen/Dienste anzuzeigen, aktuelle Zustimmungen zu lesen und UI-Schalter entsprechend vorzubelegen. Außerdem kann damit erreicht werden, dass Embeds/Tracker erst nach Einwilligung geladen werden. **Beispiel-Aufruf, der alle im Shop definierten Einwilligungsgruppen lädt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/config/consent ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "groups": [ { "allowed": false, "description": "Sind Sie überhaupt ein Mensch?", "label": "Captcha", "name": "captcha", "services": [ { "allowed": false, "description": "Google prüft gerne im Austausch Ihrer Daten ob Sie ein Mensch oder Roboter sind.", "label": "Google reCAPTCHA v3", "name": "recaptchav3" }, { "allowed": false, "description": "Bist du ein Roboter? Wenn nein wird es nicht schwierig.", "label": "Friendly Captcha V1", "name": "friendlyCaptchaV1" } ] }, { "allowed": false, "description": "Medien liegen uns am Herzen!", "label": "Medien", "name": "media", "services": [ { "allowed": false, "description": "Wir haben ein Video auf Youtube über uns, das wir Ihnen gerne zeigen würden.", "label": "Youtube Videos", "name": "youtube" } ] }, { "allowed": false, "description": "wir bieten verschiedene Dienstleistungen an", "label": "ShopService", "name": "shopService", "services": [ { "allowed": false, "description": "Sind Sie damit einverstanden, eine E-Mail zur Bewertung der Bestellungen zu erhalten?", "label": "Rate Reminder", "name": "ratereminder" } ] }, { "allowed": false, "description": "", "label": "Tracking", "name": "tracking", "services": [ { "allowed": false, "description": "", "label": "Econda Analytics", "name": "econda" }, { "allowed": false, "description": "", "label": "Google Analytics", "name": "google" } ] } ], "services": [ { "allowed": false, "description": "", "label": "Econda Analytics", "name": "econda" }, { "allowed": false, "description": "Bist du ein Roboter? Wenn nein wird es nicht schwierig.", "label": "Friendly Captcha V1", "name": "friendlyCaptchaV1" }, { "allowed": false, "description": "", "label": "Google Analytics", "name": "google" }, { "allowed": false, "description": "Sind Sie damit einverstanden, eine E-Mail zur Bewertung der Bestellungen zu erhalten?", "label": "Rate Reminder", "name": "ratereminder" }, { "allowed": false, "description": "Google prüft gerne im Austausch Ihrer Daten ob Sie ein Mensch oder Roboter sind.", "label": "Google reCAPTCHA v3", "name": "recaptchav3" }, { "allowed": false, "description": "Wir haben ein Video auf Youtube über uns, das wir Ihnen gerne zeigen würden.", "label": "Youtube Videos", "name": "youtube" } ] } ``` ### GET config/countries Der folgende Aufruf liefert die im Shop konfigurierten Länder inklusive ihrer ISO-Codes und Anzeigenamen. Er kann zur Befüllung von Länder-Dropdowns (Adresse, Checkout), für Validierungen sowie zur Filterung/Steuerung länderspezifischer Prozesse verwendet werden. Beispiel-Aufruf, der alle im Shop konfigurierten Länder auflistet: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/config/countries ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "nodeId": "general.country:DE", "isoAlpha2": "DE", "isoAlpha3": "DEU", "isoNum": "276", "name": "Deutschland" }, { "nodeId": "general.country:AT", "isoAlpha2": "AT", "isoAlpha3": "AUT", "isoNum": "040", "name": "Österreich" }, { "nodeId": "general.country:CH", "isoAlpha2": "CH", "isoAlpha3": "CHE", "isoNum": "756", "name": "Schweiz" }, { "nodeId": "general.country:BE", "isoAlpha2": "BE", "isoAlpha3": "BEL", "isoNum": "056", "name": "Belgien" }, { "nodeId": "general.country:IT", "isoAlpha2": "IT", "isoAlpha3": "ITA", "isoNum": "380", "name": "Italien" }, { "nodeId": "general.country:PL", "isoAlpha2": "PL", "isoAlpha3": "POL", "isoNum": "616", "name": "Polen" }, { "nodeId": "general.country:NL", "isoAlpha2": "NL", "isoAlpha3": "NLD", "isoNum": "528", "name": "Niederlande" } ] } ``` `nodeId` ist die interne Kennung des Konfigurationsknotens. ### GET config/currency Der folgende Aufruf liefert die aktuell im Shop konfigurierte Währung inklusive ISO-Code, ISO-Nummer und Währungssymbol. Er kann für Preisformatierungen, die Anzeige im Warenkorb/Checkout und für Validierungen (z. B. bei Gutscheinen oder Versandkosten) verwendet werden. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/config/currency ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "nodeId": "general.currency:eur", "isoCode": "EUR", "isoNum": "978", "symbol": "€" } ``` ### GET config/directOrder Der folgende Aufruf liefert die Shop-Konfiguration für die Direktbestellung (Schnelleingabe per Artikelnummer). Beispielsweise wird festgelegt, wie viele Anzeigereihen initial angezeigt werden, wie eine Artikelnummer aufgebaut ist (Feld/Trenner) und welche Obergrenzen gelten. Er kann zum Aufbau der Direktbestell-Maske verwendet werden. **Beispiel-Aufruf, der die Shop-Konfiguration für die Direktbestellung lädt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/config/directOrder ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "initialNumber": 5, "itemNumberFields": [ { "name": "firstField", "required": true, "type": "field" }, { "sign": "-", "type": "separator" }, { "name": "secondField", "required": false, "type": "field" } ], "maximalNumber": 1000, "refreshedNumber": 5 } ``` ### GET config/inserts Der folgende Aufruf liefert die konfigurierten Inserts (Textbausteine) des Shops. Er kann verwendet werden, um Textbausteine im Frontend auszugeben, ohne sie im Template fest zu hinterlegen. **Beispiel-Aufruf, der alle konfigurierten Inserts liefert** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/config/inserts ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response Die Antwort entspricht dem Inhalt von `$wsConfig.inserts`. ### GET config/password Folgender Aufruf liefert die aktiven Passwortregeln des Shops (z. B. Mindest-/Maximallänge, zusätzliche Prüfungen). Diese Regeln stammen aus den konfigurierten Validierungs-Services ([Validierungs- und Prüfservices](/konfiguration/validierungs-und-prufservices)). Er kann zur Anzeige und Prüfung bei Passwort-Formularen (Registrierung, Passwort ändern/zurücksetzen) verwendet werden, damit die Eingaben bereits clientseitig die Shop-Vorgaben erfüllen. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/config/password ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "checkLoginID": true, "checkOldPassword": true, "passwordChecks": { "maxLength": { "len": 15 }, "minLength": { "len": 3 } } } ``` ### GET config/paymentMethods Der folgende Aufruf liefert die im Shop verfügbaren Zahlungsarten als Liste (jeweils mit technischer ID und Anzeigenamen). Er kann zum Befüllen der Zahlungsarten-Auswahl im Checkout verwendet werden. **Beispiel-Aufruf, der alle im Shop verfügbaren Zahlungsarten auflistet** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/config/paymentMethods ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "id": "applepay", "name": "Apple Pay" }, { "id": "bill", "name": "Rechnung" }, { "id": "creditcard", "name": "Credit Card" }, { "id": "googlepay", "name": "Google Pay" }, { "id": "maxpayment", "name": "Max Rechnung" }, { "id": "minpayment", "name": "Min Rechnung" }, { "id": "paypalCheckout", "name": "PayPal Checkout" }, { "id": "paypalCheckoutApplePay", "name": "PayPal Checkout (Apple Pay)" }, { "id": "paypalCheckoutBanContact", "name": "PayPal Checkout (BanContact)" }, { "id": "paypalCheckoutBlik", "name": "PayPal Checkout (Blik)" }, { "id": "paypalCheckoutCreditCard", "name": "PayPal Checkout (Credit Card)" }, { "id": "paypalCheckoutEps", "name": "PayPal Checkout (EPS)" }, { "id": "paypalCheckoutGiroPay", "name": "PayPal Checkout (GiroPay)" }, { "id": "paypalCheckoutGooglePay", "name": "PayPal Checkout (Google Pay)" }, { "id": "paypalCheckoutIdeal", "name": "PayPal Checkout (Ideal)" }, { "id": "paypalCheckoutInvoice", "name": "PayPal Checkout (Invoice)" }, { "id": "paypalCheckoutMyBank", "name": "PayPal Checkout (MyBank)" }, { "id": "paypalCheckoutPayLater", "name": "PayPal Checkout (PayLater)" }, { "id": "paypalCheckoutPrzelewy24", "name": "PayPal Checkout (Przelewy24)" }, { "id": "paypalCheckoutSepa", "name": "PayPal Checkout (SEPA)" }, { "id": "paypalCheckoutSofort", "name": "PayPal Checkout (Sofort)" }, { "id": "paypalPlus", "name": "PayPal Plus" }, { "id": "prepayment", "name": "Vorauskasse" }, { "id": "safepayment", "name": "Sichere Zahlungsart" }, { "id": "stripe", "name": "Stripe" }, { "id": "twint", "name": "Twint" } ] } ``` ### GET config/salutation Der folgende Aufruf liefert die im Shop konfigurierten Anreden (jeweils mit Code und Anzeigetext). Er kann zum Befüllen von Auswahllisten in Formularen verwendet werden. Beispiel-Aufruf, der die im Shop konfigurierten Anreden auflistet: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/config/salutation ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "code": "1", "text": "Herr" }, { "code": "2", "text": "Frau" }, { "code": "3", "text": "Familie" }, { "code": "4", "text": "Firma" } ] } ``` ### GET config/shippingMethods Der folgende Aufruf liefert alle **aktiven** Versandarten des Shops mit technischer ID, Anzeigenamen und Typ. Er kann zum Befüllen der Versandarten-Auswahl im Checkout oder zur Anzeige verfügbarer Lieferoptionen auf Infoseiten verwendet werden. Beispiel-Aufruf, der alle im Shop verfügbaren Versandarten auflistet: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/config/shippingMethods ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "nodeId": "checkout.shippingMethod:pickup", "id": "pickup", "name": "Click & Collect", "description": "", "image": "", "link": "", "type": "pickup", "group": null }, { "nodeId": "checkout.shippingMethod:dhl", "id": "dhl", "name": "DHL", "description": "", "image": "", "link": "", "type": "standard", "group": null } ] } ``` `type` ist `standard` oder `pickup`. `group` ist `null`, wenn der Versandart keine Gruppe zugeordnet ist, sonst das Gruppenobjekt. ### GET config/title Mit dem folgenden Aufruf werden die konfigurierten Titel (z. B. akademische Titel) für die Kunden- und Adressformulare geliefert. Er kann zum Befüllen von Titel-Auswahllisten in Formularen verwendet werden. **Beispiel-Aufruf, der alle im Shop konfigurierten Titel auflistet** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/config/title ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "code": "1", "text": "" }, { "code": "2", "text": "Dr." }, { "code": "3", "text": "Prof." } ] } ``` *** ## Methoden der Subshop Konfigurationen Mithilfe dieser Methoden kann die Konfiguration des Subshops im Storefront-Kontext verwaltet werden. Sie ermitteln die aktuell aktive Subshop-ID (z. B. für Sprache oder Land), listen alle verfügbaren Subshops auf und erzeugen für einen angegebenen Subshop eine vollständige Ziel-URL. ### GET subshop/current Mit dem folgenden Aufruf wird die aktuelle Subshop-ID zum Auslesen des aktiven Subshops für sprach-/land- oder themenspezifische Inhalte, URLs und Konfigurationen an die aufrufende Storefront zurückgegeben. **Beispiel-Aufruf, der die aktuelle Subshop-ID der aufrufenden Storefront zurückgibt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/subshop/current ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "deutsch" } ``` Hinweis: Sprache, aktuelle Serverzeit und Zeitzone des Subshops stehen im Shop-Template unter `$wsSubshop.language`, `$wsSubshop.currentTime` und `$wsSubshop.timeZone` bereit. Ob `subshop/current` diese Werte mit ausliefert, ist gegen das Template `storefront-api/api/v1/subshop/current.htm` zu prüfen. ### GET subshop/list Der folgende Aufruf liefert eine Liste mit allen im Shop verfügbaren Subshops. Er kann zum Aufbauen von Sprach-/Länderauswahlen, zum Umschalten zwischen Subshops oder für das Routing/den Linkaufbau je Subshop verwendet werden. Beispiel-Aufruf, der eine Liste der verfügbaren Subshops liefert: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/subshop/list ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ "deutsch", "english" ] } ``` ### GET subshop/url Folgender Aufruf liefert die vollständige Shop-URL für einen angegebenen Subshop und übernimmt optional Zusatzparameter in die Query. Er kann für den Sprach-/Länderwechsel oder zum Generieren von Links (inkl. optionaler Parameter) verwendet werden. Beispiel-Aufruf, der die Ziel-URL für den Subshop `english` erzeugt und die Query-Parameter `key1=value1` und `key2=value2` anhängt. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/subshop/url?subshopId=english¶m[key1]=value1¶m[key2]=value2 ``` #### Parameterübersicht #### Query-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------- | | `subshopId` | string | **Pflichtfeld** ID des Ziel-Subshops (beispielsweise `english`). Ist die ID unbekannt, ist `url` in der Antwort `null`. | | `param[…]` | string | Beispiel: `param[key1]=value1¶m[key2]=value2` | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "url": "https://en..com/?key1=value1&key2=value2" } ``` # Storefront API Kundenbewertungen Source: https://dokumentation.websale.de/schnittstellen/storefront-api/storefront-api-kundenbewertungen Kundenbewertungen über die Storefront API erstellen, abrufen, aktualisieren, löschen sowie freigegebene Bewertungen und Statistiken auswerten. Die Storefront-API für Kundenbewertungen stellt Funktionen bereit, um Kundenbewertungen zu erstellen, abzurufen, zu aktualisieren, zu löschen und auszuwerten. Darüber hinaus lassen sich z.B. die eigene Bewertung eines eingeloggten Kontos, alle freigegebenen Bewertungen eines Produkts sowie Statistikwerte abfragen. Für die korrekte Verwendung der API für Kundenbewertungen muss zwingend immer eine `x-session`mitgegeben werden. Mehr dazu [hier](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling). *** ## Unterstützte Methoden Angabe aller Unterstützten Methoden. | **Befehl** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | --------------------------------------------- | -------------------------- | --------------------- | --------------------- | --------------------- | --------------------- | | Letzte Bewertung abrufen | `account/rating/latest` | | | | | | Alle Bewertungen aufrufen | `account/rating/list` | | | | | | Existenz einer Bewertung prüfen | `productRating/check` | | | | | | Eine bestimmte Bewertung abrufen | `productRating/get` | | | | | | Alle Bewertungen eines Produkts abrufen | `productRating/list` | | | | | | Bewertungsdurchschnitt eines Produkts abrufen | `productRating/statistics` | | | | | | Bewertung erstellen | `productRating/add` | | | | | | Bewertung aktualisieren | `productRating/update` | | | | | | Bewertung löschen | `productRating/update` | | | | | ## Methoden für Bewertungen innerhalb eines Kundenkontos Über diese Methoden können Bewertungen aus Sicht eines konkreten Kundenkontos abgefragt werden. Damit kann das Frontend nach einem Bewertungsvorgang die aktuelle Bewertung des Kunden anzeigen oder in „Mein Konto“-Bereichen (z. B. Übersicht eigener Bewertungen) wiederverwenden. ### GET account/rating/latest Folgender Aufruf stellt die zuletzt abgegebene Kundenbewertung des aktuell angemeldeten Kunden bereit. **Beispiel-Aufruf der zuletzt abgegebenen Kundenbewertung des eingeloggten Kontos** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/account/rating/latest ``` #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountId" : "126", "accountType" : 2, "anonymous" : false, "answeredAt" : "", "approval" : false, "createdAt" : "1970-01-01T00:00:00.000Z", "description" : "Beschreibung", "disapprovalReason" : "", "merchantComment" : "", "orderId" : "4857", "points" : 5, "productId" : "83-1782", "subject" : "Titel", "subshopId" : "deutsch" } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](../storefront-api/storefront-api-basics.md#2-session-handling) | Dieser Endpunkt setzt ein **angemeldetes** Kundenkonto voraus. Ohne gültigen `x-session`-Header oder ohne angemeldetes Konto antwortet der Endpunkt mit HTTP 400. ### GET account/rating/list Folgender Aufruf listet alle Produktbewertungen des aktuell eingeloggten Kontos auf. Der Befehl kann beispielsweise verwendet werden, um eine Bewertungsübersicht im Kundenkonto “Mein Konto” anzuzeigen. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/account/rating/list ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | Dieser Endpunkt setzt ein **angemeldetes** Kundenkonto voraus. Ohne gültigen `x-session`-Header oder ohne angemeldetes Konto antwortet der Endpunkt mit HTTP 400. #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "accountId": "126", "accountType": 2, "anonymous": false, "answeredAt": "", "approval": false, "createdAt": "1970-01-01T00:00:00.000Z", "description": "Beschreibung", "disapprovalReason": "", "merchantComment": "", "orderId": "4857", "points": 5, "productId": "12345", "subject": "Titel", "subshopId": "deutsch" } ] } ``` ## Methoden für Kundenbewertungen (pro Bestellung) Über diese Methode werden Kundenbewertungen verwaltet, die ein Kunde für ein bestimmtes Produkt innerhalb einer konkreten Bestellung abgegeben hat. Zudem können neue Bewertungen angelegt, vorhandene Bewertungen geändert oder wieder gelöscht werden. Zusätzlich stehen Prüf- und Lese-Methoden zur Verfügung, um festzustellen, ob bereits eine Bewertung für die Kombination aus Produkt und Bestellung existiert und um diese Bewertung im Detail abzurufen (z. B. nach Aufruf eines Bewertungslinks in einer Service-E-Mail). ### GET productRating/get Mit diesem Aufruf wird – sofern vorhanden – die bereits abgegebene Kundenbewertung zu der angegebenen Kombination aus Bestellung und Produkt im Detail abgerufen, um sie z. B. in Formularen oder „Mein Konto“-Ansichten anzuzeigen. **Beispiel-Aufruf um eine Kundenbewertung für das Produkt mit der ID** `99-0984 `**aus der Bestellung** `0404-12 `**abzurufen** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/productRating/get?productId=99-0984&orderId=0404-12 ``` #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "accountId": "126", "accountType": 2, "anonymous": false, "answeredAt": "", "approval": true, "createdAt": "2025-11-04T09:27:18.000Z", "description": "Beschreibung", "disapprovalReason": "", "displayName": "Max Mustermann", "memberId": "0", "merchantComment": "", "orderId": "0404-12", "points": 5, "productId": "99-0984", "subject": "Titel", "subshopId": "deutsch" } ``` Existiert keine Bewertung zu dieser Kombination, ist die Antwort leer. #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------ | | `productId` | string | **Pflichtfeld** ID des Produkts, für das die Bewertung abgegeben wurde. | | `orderId` | string | **Pflichtfeld** ID der zugehörigen Bestellung, über die die Bewertung dem Kauf zugeordnet ist. | ### GET productRating/check Mit dieser Methode wird geprüft, ob für die angegebene Kombination aus Bestellung und Produkt bereits eine Bewertung des Kunden vorliegt (z. B. zur Steuerung, ob ein Bewertungslink oder -formular noch angezeigt werden soll). **Beispiel-Aufruf um festzustellen, ob eine Kundenbewertung für das Produkt mit der ID** `99-0984 `**aus der Bestellung mit der ID** `4857 `**existiert** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/productRating/check?productId=99-0984&orderId=4857 ``` #### Beispiel-Response Beispiel-Response, wenn die Bewertung existiert, ansonsten bekommt man “`false`” zurück: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "exists": true } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `productId` | string | **Pflichtfeld** ID des Produkts, für das geprüft wird, ob eine Bewertung existiert. | | `orderId` | string | Pflichtfeld nur, wenn in der Shop-Konfiguration `general.productRating.allowRatingAfterEachOrder` aktiv ist. Ist die Einstellung nicht aktiv, wird der Parameter ignoriert und es wird nur geprüft, ob das Konto das Produkt überhaupt schon bewertet hat, unabhängig von der Bestellung. | ### POST productRating/add Mit dieser Methode wird für eine konkrete Kombination aus Bestellung `orderId` und Produkt `productId` eine neue Kundenbewertung angelegt. **Beispiel-Aufruf, der eine Kundenbewertung für das Produkt mit der ID** `99-0984 `**für die Bestellung mit der ID** `4900 `**abgibt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/productRating/add ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "productId": "99-0984", "orderId": "4900", "subject": "Titel", "description": "Meine Bewertung", "points": 5 } ``` #### Beispiel-Response ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `productId` | string | **Pflichtfeld** ID des Produkts, für das die Bewertung abgegeben werden soll. | | `orderId` | string | **Pflichtfeld** ID der Bestellung, mit der der Kauf des Produktes verbunden ist. | | `subject` | string | Pflichtfeld, wenn in `general.productRating` als solches konfiguriert, sonst optional. Kurzer Titel der Bewertung. | | `description` | string | Pflichtfeld, wenn in `general.productRating` als solches konfiguriert, sonst optional. Freitext der Bewertung. | | `points` | int | Pflichtfeld, wenn in `general.productRating` als solches konfiguriert, sonst optional. Muss zwischen der konfigurierten Minimal- und Maximalbewertung liegen. Konfiguration: [general - Allgemeine Shopeinstellungen](/konfiguration/general-allgemeine-shopeinstellungen#generalproductrating-produktbewertung) | | `categoryId` | string | Optional. Kategorie, aus der heraus die Bewertung abgegeben wurde. Wird mit der Bewertung gespeichert und ist in Auswertungen verfügbar. | | `anonymous` | string | Optional. Jeder nicht-leere Wert (beispielsweise `"1"`) veröffentlicht die Bewertung ohne persönliche Zuordnung. Für eine **nicht** anonyme Bewertung muss das Feld weggelassen oder als leerer String `""` gesendet werden. Achtung: `false` (Boolean) oder `"false"` gelten als nicht-leer und schalten die Anonymisierung **ein**. | #### Fehlercodes | **Fehlercode** | **Beschreibung** | | -------------------- | ------------------------------------------------------------------------------------- | | `notLoggedIn` | Es ist kein Kundenkonto angemeldet. | | `missingProductId` | `productId` fehlt oder ist leer. | | `missingOrderId` | `orderId` fehlt oder ist leer. | | `missingSubject` | `subject` fehlt, obwohl es in der Shop-Konfiguration als Pflichtfeld gesetzt ist. | | `missingDescription` | `description` fehlt, obwohl es in der Shop-Konfiguration als Pflichtfeld gesetzt ist. | | `missingPoints` | `points` fehlt, obwohl es in der Shop-Konfiguration als Pflichtfeld gesetzt ist. | | `invalidPoints` | `points` liegt außerhalb der konfigurierten Ober-/Untergrenze oder ist keine Zahl. | | `productNotFound` | Das angegebene Produkt existiert im aktuellen Subshop nicht. | | `orderDoesNotExist` | Die angegebene Bestellung existiert im System nicht. | | `wrongOrderId` | Die angegebene Bestellung gehört zu einem anderen Kundenkonto. | | `duplicateRating` | Es wurde schon eine Bewertung für dieses Produkt von diesem Konto abgegeben. | | `ratingNotCreated` | Die Bewertung konnte nicht gespeichert werden (interner Fehler). | ### PUT productRating/update Mit dieser Methode wird eine bereits vorhandene Kundenbewertung zu einer bestimmten Bestellung `orderId` und einem bestimmten Produkt `productId` geändert, beispielsweise wenn der Kunde Text oder Bewertungssternzahl nachträglich anpasst. Achtung: Jede Aktualisierung setzt den Freigabestatus der Bewertung auf `false` zurück. Die Bewertung ist danach so lange nicht mehr in `GET productRating/list` und in `GET productRating/statistics` enthalten, bis sie im Admin erneut freigegeben wurde. **Beispiel-Aufruf, um eine bereits vorhandene Kundenbewertung für das Produkt mit der ID** `99-0984 `**aus der Bestellung mit der ID** `4900 `**zu ändern** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} PUT https://.de/api/v1/productRating/update ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "productId": "99-0984", "orderId": "4900", "subject": "Titel", "description": "Beschreibung", "points": 5 } ``` #### Beispiel-Response ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `productId` | string | **Pflichtfeld** ID des Produkts, für das die Bewertung aktualisiert werden soll. | | `orderId` | string | **Pflichtfeld** ID der Bestellung, mit der der Kauf des Produktes verbunden ist. | | `subject` | string | Pflichtfeld, wenn in `general.productRating` als solches konfiguriert, sonst optional. Kurzer Titel der Bewertung. | | `description` | string | Pflichtfeld, wenn in `general.productRating` als solches konfiguriert, sonst optional. Freitext der Bewertung. | | `points` | int | Pflichtfeld, wenn in `general.productRating` als solches konfiguriert, sonst optional. Muss zwischen der konfigurierten Minimal- und Maximalbewertung liegen. Konfiguration: [general - Allgemeine Shopeinstellungen](/konfiguration/general-allgemeine-shopeinstellungen#generalproductrating-produktbewertung) | | `anonymous` | string | Optional. Jeder nicht-leere Wert (beispielsweise `"1"`) veröffentlicht die Bewertung ohne persönliche Zuordnung. Für eine **nicht** anonyme Bewertung muss das Feld weggelassen oder als leerer String `""` gesendet werden. Achtung: `false` (Boolean) oder `"false"` gelten als nicht-leer und schalten die Anonymisierung **ein**. | #### Fehlercodes | **Fehlercode** | **Beschreibung** | | -------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `notLoggedIn` | Es ist kein Kundenkonto angemeldet. | | `missingProductId` | `productId` fehlt oder ist leer. | | `missingOrderId` | `orderId` fehlt oder ist leer. | | `missingSubject` | `subject` fehlt, obwohl es in der Shop-Konfiguration als Pflichtfeld gesetzt ist. | | `missingDescription` | `description` fehlt, obwohl es in der Shop-Konfiguration als Pflichtfeld gesetzt ist. | | `missingPoints` | `points` fehlt, obwohl es in der Shop-Konfiguration als Pflichtfeld gesetzt ist. | | `invalidPoints` | `points` liegt außerhalb der konfigurierten Ober-/Untergrenze oder ist keine Zahl. | | `productNotFound` | Das angegebene Produkt existiert im aktuellen Subshop nicht. | | `ratingNotUpdated` | Zu dieser Kombination aus Produkt und Bestellung existiert keine Bewertung dieses Kontos, oder das Speichern ist fehlgeschlagen. | ### DELETE productRating/update Mit dieser Methode wird eine bestehende Kundenbewertung für eine konkrete Kombination aus Bestellung `orderId` und Produkt `productId` wieder gelöscht, sodass sie im Frontend nicht mehr angezeigt und in Auswertungen nicht mehr berücksichtigt wird. **Beispiel-Aufruf, um eine Kundenbewertung für das Produkt mit der ID** `99-0984 `**für die Bestellung mit der ID** `4900 `**zu löschen** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} DELETE https://.de/api/v1/productRating/update ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "productId": "99-0984", "orderId": "4900" } ``` #### Beispiel-Response ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------------------------------------------------------------- | | `productId` | string | **Pflichtfeld**
    ID des Produkts, dessen Bewertung gelöscht werden soll. | | `orderId` | string | **Pflichtfeld**
    ID der Bestellung, über die die Bewertung dem Kauf zugeordnet ist. | #### Fehlercodes | **Fehlercode** | **Beschreibung** | | ------------------ | --------------------------------------------------------------------------------------------------- | | `notLoggedIn` | Es ist kein Kundenkonto angemeldet. | | `missingProductId` | `productId` fehlt oder ist leer. | | `missingOrderId` | `orderId` fehlt oder ist leer. | | `ratingNotDeleted` | Zu dieser Kombination existiert keine Bewertung dieses Kontos, oder das Löschen ist fehlgeschlagen. | ## Methoden für Bewertungsübersichten je Produkt Diese Methoden stellen alle freigegebenen Kundenbewertungen sowie aggregierte Bewertungsinformationen für ein bestimmtes Produkt bereit. ### GET productRating/list Mit dieser Methode werden alle für das angegebene Produkt verfügbaren Kundenbewertungen abgerufen. Die zurückgegebenen Daten können im Frontend z. B. für die Anzeige einer vollständigen Bewertungsübersicht auf der Produktdetailseite oder in separaten Bewertungslisten verwendet werden. **Beispiel-Aufruf, um alle Kundenbewertungen für das Produkt mit der ID** `99-0984 `**anzeigen zu lassen** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/productRating/list?productId=99-0984 ``` **Beispiel-Response** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items" : [ { "accountId" : "126", "accountType" : 2, "anonymous" : false, "answeredAt" : "", "approval" : true, "createdAt" : "1970-01-01T00:00:00.000Z", "description" : "Beschreibung", "disapprovalReason" : "", "displayName" : "Max Mustermann", "memberId" : "0", "merchantComment" : "", "points" : 5, "productId" : "99-0984", "subject" : "Titel", "subshopId" : "deutsch" } ] } ``` Bei anonymen Bewertungen (`anonymous: true`) entfallen `accountId` und `memberId` vollständig und `displayName` ist ein leerer String. **Parameterübersicht** **Header-Parameter** | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | **Body-Parameter** | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ---------------------------------------------------------------------------------- | | `productId` | string | **Pflichtfeld**
    ID des Produkts, für das Bewertungen abgerufen werden sollen. | ### GET productRating/statistics Mit dieser Methode werden die aus allen freigegebenen Kundenbewertungen berechneten Kennzahlen für das angegebene Produkt abgerufen, insbesondere der durchschnittliche Bewertungswert und die Anzahl der berücksichtigten Bewertungen. Die Daten eignen sich insbesondere für kompakte Darstellungen wie Bewertungssterne und kurze Bewertungszusammenfassungen auf Produktdetailseiten oder Übersichtsseiten. **Beispiel-Aufruf, um die Statistik für die Kundenbewertungen für das Produkt mit der ID** `99-0984 `**zu laden** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/productRating/statistics?productId=99-0984 ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ---------------------------------------------------------------------------------- | | `productId` | string | **Pflichtfeld**
    ID des Produkts, für das Bewertungen abgerufen werden sollen. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "averageRating" : 5, "productId" : "99-0984", "totalRatingCount" : 1 } ``` # Storefront API Kundenkonto Source: https://dokumentation.websale.de/schnittstellen/storefront-api/storefront-api-kundenkonto Bereich „Mein Konto“ über die Storefront API verwalten: Login, Registrierung, Adressen, Passwort-Reset, Bestellhistorie und Verfügbarkeitsalarme. Die Kundenkonto API stellt die Funktionen für den Bereich „Mein Konto“ bereit. Dazu gehören die Verwaltung persönlicher Daten, Zugangsdaten und Adressen (Adressbuch anlegen/ändern/löschen) sowie typische Account-Prozesse wie E-Mail-Änderung (inklusive Double-Opt-In), Passwort ändern/zurücksetzen („Passwort vergessen“) und das Löschen des Kontos. Zusätzlich können kundenbezogene Informationen wie Bestellhistorie (Online-Bestellungen) bereitgestellt werden. Weitere typische Funktionen sind das Anlegen und Verwalten von Verfügbarkeitsalarmen, eine Übersicht eigener Bewertungen sowie Login, Registrierung und – sofern vorgesehen – persistente Sitzungen („eingeloggt bleiben“). Sämtliche Aufrufe erfordern eine aktive Session per `x-session`. Mehr dazu *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | ------------------------------------------------------------ | ---------------------------- | --------------------- | --------------------- | --------------------- | --------------------- | | Kundenkonto einloggen | `account/login` | | | | | | Angemeldet bleiben aktivieren | `account/autologin` | | | | | | Kundenkonto anlegen | `account/register` | | | | | | Kontodaten abfragen | `account/get` | | | | | | Kundenkonto ausloggen | `account/logout` | | | | | | Kundenkonto löschen | `account/delete` | | | | | | Kundenkonto löschen mit Opt-In-Code | `account/deleteConfirm` | | | | | | Neue Adresse zum Kundenkonto hinzufügen | `account/address/create` | | | | | | Eine bestehende Adresse bearbeiten | `account/address/update` | | | | | | Adresse als Hauptadresse setzen | `account/address/setMain` | | | | | | Adresse des Kundenkontos auflisten | `account/address/list` | | | | | | Eine bestimmte Adresse abrufen | `account/address/get` | | | | | | Eine Adresse löschen | `account/address/delete` | | | | | | Benachrichtigung, für “Produkt wieder vorrätig” aktivieren | `account/backInStock/notify` | | | | | | Alle “Produkt wieder verfügbar” Benachrichtigungen auflisten | `account/backInStock/list` | | | | | | Anzeigenamen bei Produktbewertungen ändern | `account/displayName/update` | | | | | | E-Mail-Adresse des Kundenkontos ändern | `account/email/update` | | | | | | E-Mail-Adresse des Kundenkontos verifizieren | `account/email/verify` | | | | | | Alle Bestellungen des Kundenkontos auflisten | `account/order/list` | | | | | | Eine bestimmte Bestellung abrufen | `account/order/get` | | | | | | Das Passwort des Kundenkontos ändern | `account/password/change` | | | | | | Passwort-Zurücksetzung starten | `account/password/forgotten` | | | | | | Passwort zurücksetzen | `account/password/reset` | | | | | | Eigene Produktbewertungen auflisten | `account/rating/list` | | | | | ## Methoden für das Kundenkonto Mithilfe dieser Methoden wird das Kundenkonto im Shop verwaltet. Sie lesen die Daten des aktuell eingeloggten Benutzers (Stammdaten, Adresse, Kundendatenfelder, Login-Status) aus und melden ein Konto mit E-Mail-Adresse/Passwort an. Optional kann die Funktion „Angemeldet bleiben” per Autologin-Token aktiviert werden. Darüber hinaus können neue Konten registriert und direkt eingeloggt werden. Bestehende Sessions lassen sich sauber abmelden. Zudem können Kundenkonten gelöscht werden. ### GET account/get Mit diesem Aufruf werden die Daten des aktuell eingeloggten Kundenkontos der übergebenen Session ausgeliefert. Typische Einsatzzwecke sind die Anzeige des Kontobereichs (Name, E-Mail-Adresse, Anzeigename) oder eine einfache „Angemeldet/Abgemeldet“-Prüfung im Frontend. Beispiel Aufruf, um Daten des aktuell eingeloggten Kundenkontos zu erhalten: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/account/get ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "addresses" : [ { "additionalInfo" : "", "addressType" : "1", "businessFax" : "", "businessPhone" : "", "city" : "Nürnberg", "company" : "", "country" : "DE", "custom" : {}, "dateOfBirth" : "", "department" : "", "fax" : "", "firstName" : "Maria", "id" : "85", "isBillAddress" : true, "isDefaultBillAddress" : true, "isDeliveryAddress" : false, "isDefaultDeliveryAddress" : false, "isReadonly" : false, "lastName" : "Musterfrau", "mobilePhone" : "", "phone" : "", "salutationCode" : "2", "state" : "", "street" : "Gutenstetterstraße 2", "streetNumber" : "", "taxId" : "", "titleCode" : "", "zip" : "90449" } ], "allowedSubshops" : [ "deutsch" ], "autoLogInRestriction" : "restricted", "backInStockList" : [], "blockedPaymentMethods" : [], "canSeePrices" : true, "currentSubAccount" : null, "customerData" : { "groupedFields" : [ { "fields" : [ { "association" : "hybrid", "label" : "Ausgangsspannung", "name" : "outputVoltage", "type" : "text", "value" : "230 V" } ], "hidden" : false, "label" : "Geräteinformationen", "name" : "applianceInformation" } ], "newCustomerFieldGroups" : [], "ungroupedFields" : [ { "association" : "shopAccount", "label" : "Kundengruppe", "name" : "customerGroup", "options" : [ { "label" : "Hundehalter", "value" : "dog" }, { "label" : "Katzenhalter", "value" : "cat" } ], "type" : "select", "value" : "" } ] }, "defaultBillAddress" : null, "defaultDeliveryAddress" : null, "displayName" : "", "email" : "kundenkonto@example.com", "enabledPaymentMethods" : [ "bill" ], "id" : 51, "isAccountVerified" : false, "isAdmin" : false, "isAutoLogInRestricted" : true, "isAutoLoggedIn" : false, "isLoggedIn" : true, "isPasswordResetRequired" : false, "lastLogin" : "2025-11-04T08:42:20.996Z", "mainAddress" : { "additionalInfo" : "", "addressType" : "1", "businessFax" : "", "businessPhone" : "", "city" : "Nürnberg", "company" : "", "country" : "DE", "custom" : {}, "dateOfBirth" : "", "department" : "", "fax" : "", "firstName" : "Maria", "id" : "85", "lastName" : "Musterfrau", "mobilePhone" : "", "phone" : "", "salutationCode" : "2", "state" : "", "street" : "Gutenstetterstraße 2", "streetNumber" : "", "taxId" : "", "titleCode" : "", "zip" : "90449" }, "memberId" : 0, "paymentLimit" : 5000, "paymentLimitPerOrder" : 1000, "privilegeGroups" : [], "pseudoCreditCards" : [], "subAccounts" : [], "typeSeparation" : { "enabled" : false, "canCreateBillAddress" : true, "maxBillAddresses" : 5, "defaultBillAddressReadonly" : false } } ``` Die fünf Felder `isBillAddress`, `isDefaultBillAddress`, `isDeliveryAddress`, `isDefaultDeliveryAddress` und `isReadonly` stehen nur an den Einträgen der Liste `addresses`, nicht an `mainAddress`. Jede Gruppe in `groupedFields` trägt zusätzlich das Feld `hidden`, und `customerData` enthält immer den zusätzlichen Schlüssel `newCustomerFieldGroups`. Die Felder `ungroupedFields`, `newCustomerFields` und `existingCustomerFields` innerhalb von `customerData` sind nur enthalten, wenn `customer.customerDataFieldSettings.showUngroupedFields` aktiviert ist. ### B2B-Unterkonten Für Kundenkonten mit aktivierten B2B-Unterkonten (`accounts.subAccountsEnabled`) liefert `$wsAccount` zusätzliche Felder auf oberster Ebene, sobald die Session eingeloggt ist. | **Feld** | **Typ** | **Beschreibung** | | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------ | | `memberId` | int | ID des angemeldeten Unterkontos. `0` beim Hauptkonto. | | `isAdmin` | boolean | Ob das angemeldete Unterkonto Firmen-Admin ist und damit firmenweite Einstellungen wie die Hauptadresse ändern darf. | | `subAccounts` | array | Liste der Unterkonten des Kundenkontos. Nur enthalten, wenn B2B-Unterkonten aktiv sind. | | `currentSubAccount` | object | Das aktuell angemeldete Unterkonto. Nur enthalten, wenn B2B-Unterkonten aktiv sind. | | `privilegeGroups` | array | Rechtegruppen, die einem Unterkonto zugewiesen werden können. Nur enthalten, wenn B2B-Unterkonten aktiv sind. | | `paymentLimit` | int | Gesamt-Zahlungslimit des Kontos. Liegt direkt auf oberster Ebene von `$wsAccount`, nicht in einem Budget-Objekt verschachtelt. | | `paymentLimitPerOrder` | int | Zahlungslimit je Bestellung. Liegt ebenfalls direkt auf oberster Ebene von `$wsAccount`. | ### POST account/login Mit diesem Aufruf wird ein Kundenkonto angemeldet. Sind die übergebenen Zugangsdaten korrekt, wird die aktive Sitzung in den Account eingeloggt. Wenn `Autologin` aktiviert ist, enthält die Antwort einen `Autologin-Token`. **Beispiel-Aufruf, der das Kundenkonto mit der ID** `kundenkonto@example.com`**an der Session anmeldet** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/account/login ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "kundenkonto@example.com", "password": "password123", "autologin": "off" } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `id` | string | **Pflichtfeld**
    E-Mail-Adresse des Benutzerkontos. | | `password` | string | **Pflichtfeld**
    Passwort des Benutzerkontos. | | `autologin` | enum | Steuert den Auto-Login.
    - `all` = Der Benutzer kann sich auf diesem Gerät erneut, ohne erneute Passworteingabe, anmelden
    - `restricted` = Autologin ist aktiv, für sicherheitskritische Aktionen (beispielsweise eine Passwortänderung) muss das Passwort erneut eingegeben werden
    - `off` = löscht ein vorhandenes Autologin-Token dieses Geräts. Wird `autologin` weggelassen, bleibt ein bereits gespeichertes Token unverändert bestehen, weglassen ist also nicht dasselbe wie `off` | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "account": { "id": 51, "email": "kundenkonto@example.com", "displayName": "", "isLoggedIn": true, "lastLogin": "2025-10-30T08:50:13.396Z" }, "autologinToken": null } ``` #### Fehlercodes | **Code** | **Beschreibung** | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `emailCheckFailed` | Die übergebene `id` ist keine gültige E-Mail-Adresse. | | `loginBlocked` | Das Konto ist vorübergehend gesperrt (z.B. wegen zu vieler Anmeldeversuche). | | `invalidCredentials` | E-Mail oder Passwort ungültig. | | `ipAddressBlocked` | IP aufgrund zu vieler Fehlerversuche temporär gesperrt. | | `missingId` | `id` fehlt oder ist leer. | | `missingPassword` | `password` fehlt oder ist leer. | | `passwordNotSet` | Für dieses B2B-Unterkonto wurde noch kein Passwort gesetzt. Der Benutzer muss zuerst den Einladungs- oder Passwort-Link nutzen. | ### POST account/autologin Durch diesen Aufruf wird für die aktuelle Sitzung die Funktion „Angemeldet bleiben“ aktiviert. Dadurch kann sich der Nutzer auf diesem Gerät künftig ohne erneute Passworteingabe wieder anmelden. **Beispiel-Aufruf, der Autologin für das Kundenkonto mit der ID** `51 `**aktiviert** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/account/autologin ``` #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "account": { "id": 51, "email": "kundenkonto@example.com", "displayName": "", "isLoggedIn": true, "lastLogin": "2025-10-30T08:50:13.396Z" } } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | -------------------------------------------------------------------------------------------------------------- | | `token` | string | **Pflichtfeld**
    Autologin-Token aus `POST /api/v1/account/login`
    (bei `autologin = all/restricted`). | #### Fehlercodes | **Code** | **Beschreibung** | | -------------- | ------------------------------------------------- | | `invalidToken` | Das Autologin-Token ist ungültig oder abgelaufen. | ### POST account/register Mit diesem Aufruf wird ein neues Kundenkonto erstellt und die aktuelle Sitzung direkt mit diesem Konto angemeldet. Somit kann der Nutzer nach der Registrierung sofort weitermachen. **Beispiel-Aufruf um ein neues Kundenkonto mit der E-Mail-Adresse** `kundenkonto@example.com `**und dem Passwort** `password123 `**zu erstellen** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/account/register ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "kundenkonto@example.com", "password": "password123", "passwordRepeat": "password123" } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ---------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------- | | `email` | string | **Pflichtfeld**
    E-Mail-Adresse für das neue Benutzerkonto. | | `password` | string | **Pflichtfeld**
    Passwort für das neue Benutzerkonto. | | `passwordRepeat` | string | **Pflichtfeld**
    Wiederholung des Passworts. Muss exakt mit `password` übereinstimmen, sonst kommt der Fehler `passwordMismatch`. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "account": { "id": 124, "email": "kundenkonto@example.com", "displayName": "", "isLoggedIn": true } } ``` #### Fehlercodes | **Code** | **Beschreibung** | | ---------------------- | ------------------------------------------------------------------- | | `emailCheckFailed` | Die angegebene E-Mail-Adresse ist syntaktisch ungültig. | | `loginBlocked` | Das Konto / die Anfrage ist aktuell gesperrt. | | `passwordCheckFailed` | Das Passwort erfüllt die Sicherheitsrichtlinien nicht (zu schwach). | | `accountAlreadyExists` | Es existiert bereits ein Konto mit dieser E-Mail-Adresse. | | `missingId` | `email` fehlt oder ist leer. | | `missingPassword` | `password` fehlt oder ist leer. | | `passwordMismatch` | `password` und `passwordRepeat` stimmen nicht überein. | Sind in `customer.customerDataField` Pflicht-Kundendatenfelder konfiguriert, müssen deren Werte im selben Request mitgeschickt werden. Andernfalls schlägt die Registrierung mit Feldfehlern zu diesen Feldern fehl. ### POST account/logout **Mit diesem Aufruf wird der aktuell angemeldete Benutzer ausgeloggt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/account/logout ``` #### Beispiel-Response ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Fehlercodes | **Code** | **Beschreibung** | | -------- | ---------------------------------------------------------------------------------- | | -- | Für diesen Request existieren keine Fehlercodes, die Aktion ist immer erfolgreich. | ### DELETE account/delete Mit diesem Aufruf wird das aktuell eingeloggte Kundenkonto gelöscht. Nach erfolgreicher Ausführung wird die Sitzung beendet und der Zugang zum Konto entfernt. Achtung: Die Löschung kann nicht rückgängig gemacht werden! **Beispiel-Aufruf um das aktuell eingeloggte Benutzerkonto dauerhaft zu löschen** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} DELETE https://.de/api/v1/account/delete ``` Hinweis: Je nach Shop-Konfiguration kann eine E-Mail-Bestätigung (Double-Opt-In) erforderlich sein! Siehe hier (Einstellung `doubleOptInEmail.enabled`). **Beispiel-Response** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` **Parameterübersicht** **Header-Parameter** | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | **Fehlercodes** | **Code** | **Beschreibung** | | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | | `notLoggedIn` | Es ist kein Benutzer eingeloggt. | | `actionNotAllowed` | Der übergebene Opt-In-Token ist für diese Aktion nicht erlaubt, z.B. weil er für eine andere Aktion angefordert wurde oder ungültig ist. | ### DELETE account/deleteConfirm Mit diesem Aufruf bestätigt man die Kontolöschung per `Opt-In-Token` und löschen das aktuell eingeloggte Kundenkonto endgültig. Er wird nur verwendet, wenn in Ihrem Shop die Kontolöschung per `Double-Opt-In` aktiviert ist. Ohne `Double-Opt-In` genügt der Aufruf von `account/delete`. **Beispiel-Aufruf, der die Löschung des aktuell eingeloggten Benutzerkonto per** `Opt-In-Token `**bestätigt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} DELETE https://.de/api/v1/account/deleteConfirm ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "otok": AZ3XHlWGe4E98D4fsJrPhWclSgBBQwAAAAA.ZKgwbjF-IDLuaakADfazRmAWTmjdH-A9W92JtZnPVPQ" } ``` #### Beispiel-Response ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------------------------------------- | | `otok` | string | **Pflichtfeld**
    Opt-In Token aus der Bestätigungsmail. | #### Fehlercodes | **Code** | **Beschreibung** | | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | | `notLoggedIn` | Es ist kein Benutzer eingeloggt. | | `actionNotAllowed` | Der übergebene Opt-In-Token ist für diese Aktion nicht erlaubt, z.B. weil er für eine andere Aktion angefordert wurde oder ungültig ist. | ### GET account/rating/list Mit diesem Aufruf werden alle Produktbewertungen des aktuell eingeloggten Kundenkontos aufgelistet. Er kann verwendet werden, um dem Kunden im Kundenkonto eine Übersicht seiner eigenen Bewertungen anzuzeigen. **Beispiel-Aufruf, der alle Produktbewertungen des aktuell eingeloggten Kundenkontos auflistet** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/account/rating/list ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [] } ``` #### Fehlercodes | **Code** | **Beschreibung** | | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | -- | Für diesen Request existieren keine strukturierten Fehlercodes. Ist die Session in kein Konto eingeloggt, liefert der Endpunkt den Status 400. Wird eine andere HTTP-Methode als GET verwendet, liefert der Endpunkt den Status 404. | *** ## Methoden für die Adressverwaltung Mithilfe dieser Methoden können die Adressen im Kundenkonto verwaltet werden. Sie listen alle verfügbaren Adressfelder auf und geben die zum eingeloggten Konto gehörenden Adressen zurück oder holen eine einzelne Adresse per ID ab. Neue Adressen können mit allen relevanten Feldern angelegt, bestehende Adressen gezielt aktualisiert oder als Hauptadresse markiert werden. Bei Bedarf können sie wieder gelöscht werden. ### GET account/address/fields Mit diesem Aufruf werden alle verfügbaren Adressfelder geliefert. Mithilfe dieser Informationen können Adressformulare im Frontend erstellt werden. **Beispiel-Aufruf, der alle verfügbaren Adressfelder zurückgibt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/account/address/fields ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items" : [ { "nodeId" : "addressField1", "dataId" : "addressType", "label" : "Address-Typ", "name" : "addressType" }, { "nodeId" : "addressField2", "dataId" : "firstName", "label" : "", "name" : "firstName" }, { "nodeId" : "addressField3", "dataId" : "additionalInfo", "label" : "", "name" : "additionalInfo" }, { "nodeId" : "addressField4", "dataId" : "businessFax", "label" : "", "name" : "businessFax" }, { "nodeId" : "addressField5", "dataId" : "businessPhone", "label" : "", "name" : "businessPhone" }, { "nodeId" : "addressField6", "dataId" : "city", "label" : "", "name" : "city" }, { "nodeId" : "addressField7", "dataId" : "company", "label" : "", "name" : "company" }, { "nodeId" : "addressField8", "dataId" : "country", "label" : "", "name" : "country" }, { "nodeId" : "addressField9", "dataId" : "dateOfBirth", "label" : "", "name" : "dateOfBirth" }, { "nodeId" : "addressField10", "dataId" : "department", "label" : "", "name" : "department" }, { "nodeId" : "addressField11", "dataId" : "fax", "label" : "", "name" : "fax" }, { "nodeId" : "addressField12", "dataId" : "lastName", "label" : "", "name" : "lastName" }, { "nodeId" : "addressField13", "dataId" : "mobilePhone", "label" : "", "name" : "mobilePhone" }, { "nodeId" : "addressField14", "dataId" : "phone", "label" : "", "name" : "phone" }, { "nodeId" : "addressField15", "dataId" : "salutationCode", "label" : "", "name" : "salutationCode" }, { "nodeId" : "addressField16", "dataId" : "state", "label" : "", "name" : "state" }, { "nodeId" : "addressField17", "dataId" : "street", "label" : "", "name" : "street" }, { "nodeId" : "addressField18", "dataId" : "streetNumber", "label" : "", "name" : "streetNumber" }, { "nodeId" : "addressField19", "dataId" : "taxId", "label" : "", "name" : "taxId" }, { "nodeId" : "addressField20", "dataId" : "titleCode", "label" : "", "name" : "titleCode" }, { "nodeId" : "addressField21", "dataId" : "zip", "label" : "", "name" : "zip" } ] } ``` Jeder Feldeintrag trägt zusätzlich die `nodeId` des zugehörigen Konfigurations-Nodes. Die Liste enthält zuerst die konfigurierten Standard-Adressfelder (`accounts.addressField`) und danach die kundenspezifischen Felder (`accounts.customAddressField`). ### GET account/address/list Mit diesem Aufruf werden alle gespeicherten Adressen des aktuell angemeldeten Kundenkontos inklusive der Feldwerte Name, Straße, PLZ/Ort und Ländercode zurückgeliefert. Die Daten können genutzt werden, um Adressübersichten im Kundenkonto anzuzeigen. **Beispiel-Aufruf, der alle gespeicherten Adressen des aktuellen eingeloggten Benutzerkontos zurückgibt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/account/address/list ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items" : [ { "additionalInfo" : "", "addressType" : "1", "businessFax" : "", "businessPhone" : "", "city" : "Nürnberg", "company" : "", "country" : "DE", "custom" : {}, "dateOfBirth" : "", "department" : "", "fax" : "", "firstName" : "Max", "id" : "97", "isBillAddress" : true, "isDefaultBillAddress" : true, "isDeliveryAddress" : false, "isDefaultDeliveryAddress" : false, "isReadonly" : false, "lastName" : "Mustermann", "mobilePhone" : "", "phone" : "", "salutationCode" : "2", "state" : "", "street" : "Gutenstetterstraße", "streetNumber" : "2", "taxId" : "", "titleCode" : "", "zip" : "90449" } ] } ``` ### GET account/address/get Mit folgendem Aufruf wird die konkrete Adresse des aktuell angemeldeten Kundenkontos anhand seiner Adress-ID zurückgeliefert. Diese kann beispielsweise zur Anzeige oder Vorbelegung der Adresse im Checkout verwendet werden. Beispiel-Aufruf, der die Adresse mit der ID `97` des angemeldeten Benutzerkontos zurückgibt: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET /api/v1/account/address/get?addressId=97 ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Query-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `addressId` | string | **Pflichtfeld**
    ID der Adresse, die abgerufen werden soll. Wird als Query-Parameter übergeben, beispielsweise `?addressId=97`. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "additionalInfo" : "", "addressType" : "1", "businessFax" : "", "businessPhone" : "", "city" : "Nürnberg", "company" : "", "country" : "DE", "custom" : {} "dateOfBirth" : "", "department" : "", "fax" : "", "firstName" : "Max", "id" : "97", "lastName" : "Mustermann", "mobilePhone" : "", "phone" : "", "salutationCode" : "2", "state" : "", "street" : "Gutenstetterstraße", "streetNumber" : "2", "taxId" : "", "titleCode" : "", "zip" : "90449" } ``` ### POST account/address/create Mit diesem Aufruf wird eine neue Adresse für das aktuell angemeldete Kundenkonto angelegt. Diese kann beispielsweise als Rechnungs- oder Lieferadresse im Checkout verwendet werden. **Beispiel-Aufruf, der für das aktuell eingeloggte Benutzerkonto eine neue Adresse erstellt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/account/address/create ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "address": { "firstName": "Maria", "lastName": "Musterfrau", "street": "Gutenstetterstraße", "streetNumber": "2", "zip": "90449", "city": "Nürnberg" } } ``` Hinweis: Wird nur `address` ohne angegebene Parameter übergeben, so werden für alle Felder die Standardwerte übernommen. #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ---------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `address` | object | **Pflichtfeld**
    Fasst die Adressdatenfelder zusammen. | | `type` | string | Pflichtfeld, wenn die Adresstyp-Trennung aktiv ist (`typeSeparation.enabled = true`).
    Adress-Pool: `bill` (Rechnungsadresse) oder `delivery` (Lieferadresse). Fehlt der Wert, kommt `missingAddressType`, bei anderen Werten `invalidAddressType`. | | `addressType` | string | Art der Adresse. `1` = Privat, `2` = Firma, `3` = Packstation. | | `salutationCode` | string | Anrede-Code (Werte aus `salutation.codeList`). | | `titleCode` | string | Titel-Code. | | `additionalInfo` | string | Zusatzinfos zur Adresse (z.B. Etage). | | `businessFax` | string | Fax geschäftlich. | | `businessPhone` | string | Telefon geschäftlich. | | `city` | string | Wohnort | | `company` | string | Firma / Unternehmen | | `country` | string | Ländercode (z.B. `DE )` | | `custom` | object | Freie Zusatzfelder (konfigurierbar mit `accounts.customAddressField`) | | `dateOfBirth` | string | Geburtsdatum | | `department` | string | Abteilung (Geschäftlich) | | `fax` | string | Fax privat | | `firstName` | string | Vorname | | `lastName` | string | Nachname | | `mobilePhone` | string | Handynummer | | `phone` | string | Festnetznummer | | `state` | string | Bundesland / Region | | `street` | string | Straße | | `streetNumber` | string | Hausnummer | | `taxId` | string | Steuer-/USt-ID | | `zip` | string | Postleitzahl | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "addresses" : [ { "additionalInfo" : "", "addressType" : "1", "businessFax" : "", "businessPhone" : "", "city" : "Nürnberg", "company" : "", "country" : "DE", "custom" : {}, "dateOfBirth" : "", "department" : "", "fax" : "", "firstName" : "Maria", "id" : "97", "isBillAddress" : true, "isDefaultBillAddress" : true, "isDeliveryAddress" : false, "isDefaultDeliveryAddress" : false, "isReadonly" : false, "lastName" : "Musterfrau", "mobilePhone" : "", "phone" : "", "salutationCode" : "2", "state" : "", "street" : "Gutenstetterstraße", "streetNumber" : "2", "taxId" : "", "titleCode" : "", "zip" : "90449" } ] } ``` #### Fehlercodes | **Code** | **Beschreibung** | | ------------------------- | --------------------------------------------------------------------------------------- | | `notLoggedIn` | Die Session ist in kein Konto eingeloggt (evtl. fehlende ungültige `x-session`) | | `emptyAddress` | Das Feld `address`fehlt oder ist leer. | | `unknownField` | Es existiert kein Adressfeld mit dem angegebenen Namen. | | `invalidFieldType` | Ein Adressfeld hat einen ungültigen Datentyp (z.B. Zahl statt Zeichenkette) | | `missingAddressType` | Adresstyp-Trennung ist aktiv, aber `address.type` fehlt. | | `invalidAddressType` | `address.type` hat einen anderen Wert als `bill` oder `delivery`. | | `noPermission` | Ein B2B-Unterkonto ohne Admin-Recht versucht, eine Rechnungsadresse anzulegen. | | `maxBillAddressesReached` | Die maximale Anzahl Rechnungsadressen (`typeSeparation.maxBillAddresses`) ist erreicht. | ### POST account/address/setMain Mit dieser Anfrage kann eine bestehende Adresse des aktuell eingeloggten Kundenkontos als Hauptadresse festgelegt werden (z. B. als Standard für Versand/Rechnung). Sie kann verwendet werden, um eine Adresse als Standard für Rechnung oder Versand zu kennzeichnen. Voraussetzung: Die Adresstyp-Trennung muss aktiv sein (`typeSeparation.enabled = true`, siehe `$wsAccount.typeSeparation`). Ist sie inaktiv, wird der Aufruf ohne Fehlermeldung ignoriert und die Hauptadresse bleibt unverändert. **Beispiel-Aufruf, der die Adresse mit der ID** `97 `**für das aktuell eingeloggte Kundenkonto als Hauptadresse setzt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/account/address/setMain ``` #### Beispiel-Request ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {"addressId": "97"} ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------ | | `addressId` | string | **Pflichtfeld**
    ID der Adresse, die als Hauptadresse gesetzt werden soll. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "addresses" : [ { "additionalInfo" : "", "addressType" : "1", "businessFax" : "", "businessPhone" : "", "city" : "Nürnberg", "company" : "", "country" : "DE", "custom" : {}, "dateOfBirth" : "", "department" : "", "fax" : "", "firstName" : "Maria", "id" : "97", "isBillAddress" : true, "isDefaultBillAddress" : true, "isDeliveryAddress" : false, "isDefaultDeliveryAddress" : false, "isReadonly" : false, "lastName" : "Musterfrau", "mobilePhone" : "", "phone" : "", "salutationCode" : "2", "state" : "", "street" : "Gutenstetterstraße", "streetNumber" : "2", "taxId" : "", "titleCode" : "", "zip" : "90449" } ], "mainAddress" : { "additionalInfo" : "", "addressType" : "1", "businessFax" : "", "businessPhone" : "", "city" : "Nürnberg", "company" : "", "country" : "DE", "custom" : {}, "dateOfBirth" : "", "department" : "", "fax" : "", "firstName" : "Maria", "id" : "97", "lastName" : "Musterfrau", "mobilePhone" : "", "phone" : "", "salutationCode" : "2", "state" : "", "street" : "Gutenstetterstraße", "streetNumber" : "2", "taxId" : "", "titleCode" : "", "zip" : "90449" } } ``` #### Fehlercodes | **Code** | **Beschreibung** | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | | `notLoggedIn` | Die Session ist in kein Konto eingeloggt. (fehlende / ungültige `x-session`) | | `invalidAddressId` | Die angegebene Adress-ID ist ungültig. | | `missingAddressId` | `addressId` fehlt oder ist leer. | | `noPermission` | Der eingeloggte Benutzer ist ein B2B-Unterkonto ohne Admin-Recht. Die Hauptadresse ist firmenweit und darf nur vom Firmen-Admin gesetzt werden. | ### PUT account/address/update Mit diesem Aufruf kann eine bestehende Adresse des aktuell eingeloggten Kundenkontos aktualisiert werden. Es müssen nicht alle Felder ausgefüllt werden, nicht ausgefüllte Felder bleiben unverändert. Er kann beispielsweise verwendet werden, um eine Adresse für den Versand oder die Rechnung zu korrigieren. **Beispiel-Aufruf, der für das aktuell eingeloggte Kundenkonto bei der Adresse mit der ID** `97 `**den Vor- und Nachnamen ändert** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} PUT https://.de/api/v1/account/address/update ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "addressId": "97", "address": { "firstName": "Max", "lastName": "Mustermann" } } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ---------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------- | | `addressId` | string | **Pflichtfeld**
    ID der zu ändernden Adresse. Fehlt sie, kommt `missingAddressId`, bei unbekannter ID `invalidAddressId`. | | `address` | object | **Pflichtfeld** Fasst die Adressdatenfelder zusammen. | | `type` | string | Nur bei aktiver Adresstyp-Trennung: wechselt den Adress-Pool (`bill` oder `delivery`). | | `additionalInfo` | string | Zusatzinfos zur Adresse (z.B. Etage). | | `businessFax` | string | Fax geschäftlich. | | `businessPhone` | string | Telefon geschäftlich. | | `city` | string | Wohnort | | `company` | string | Firma / Unternehmen | | `country` | string | Ländercode (z.B. `DE )` | | `custom` | object | Freie Zusatzfelder (konfigurierbar mit `accounts.customAddressField`) | | `dateOfBirth` | string | Geburtsdatum | | `department` | string | Abteilung (Geschäftlich) | | `fax` | string | Fax privat | | `firstName` | string | Vorname | | `lastName` | string | Nachname | | `mobilePhone` | string | Handynummer | | `phone` | string | Festnetznummer | | `state` | string | Bundesland / Region | | `street` | string | Straße | | `streetNumber` | string | Hausnummer | | `taxId` | string | Steuer-/USt-ID | | `zip` | string | Postleitzahl | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "addresses" : [ { "additionalInfo" : "", "addressType" : "1", "businessFax" : "", "businessPhone" : "", "city" : "Nürnberg", "company" : "", "country" : "DE", "custom" : {}, "dateOfBirth" : "", "department" : "", "fax" : "", "firstName" : "Max", "id" : "97", "isBillAddress" : true, "isDefaultBillAddress" : true, "isDeliveryAddress" : false, "isDefaultDeliveryAddress" : false, "isReadonly" : false, "lastName" : "Mustermann", "mobilePhone" : "", "phone" : "", "salutationCode" : "2", "state" : "", "street" : "Gutenstetterstraße", "streetNumber" : "2", "taxId" : "", "titleCode" : "", "zip" : "90449" } ] } ``` #### Fehlercodes | **Code** | **Beschreibung** | | ------------------ | ------------------------------------------------------------------------------------------------------------------- | | `invalidAddressId` | Die angegebene Adress-ID ist ungültig. | | `emptyAddress` | Das Feld `address`fehlt oder ist leer. | | `unknownField` | Es existiert kein Adressfeld mit dem angegebenen Namen. | | `invalidFieldType` | Ein Adressfeld hat einen ungültigen Datentyp (z.B. Zahl statt Zeichenkette) | | `readOnlyField` | Ein übergebenes Adressfeld ist schreibgeschützt und darf nicht geändert werden. Der Feldname steht im Fehlerobjekt. | ### DELETE account/address/delete Mit diesem Aufruf wird eine bestehende Adresse des aktuell eingeloggten Kundenkontos gelöscht. **Beispiel-Aufruf, der die Adresse mit der ID** `97 `**für das aktuell angemeldete Kundenkonto löscht** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} DELETE https://.de/api/v1/account/address/delete ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {"addressId": "97"} ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------------------- | | `addressId` | string | ID der Adresse, die gelöscht werden soll. | #### Beispiel-Response ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "addresses": [] } ``` #### Fehlercodes | **Code** | **Beschreibung** | | ------------------ | ---------------------------------------------------------------------------- | | `notLoggedIn` | Die Session ist in kein Konto eingeloggt. (fehlende / ungültige `x-session`) | | `invalidAddressId` | Die angegebene Adress-ID ist ungültig. | *** ## Methoden für Benachrichtigungen Mithilfe dieser Methoden können „Produkt wieder verfügbar“-Benachrichtigungen im Kundenkonto verwaltet werden. Sie lesen alle für das eingeloggte Kundenkonto hinterlegten Benachrichtigungen aus, legen neue Benachrichtigungen für eine Kombination aus E-Mail-Adresse und Produkt an und löschen bestehende Benachrichtigungen wieder. ### GET account/backInStock/list Mit folgendem Aufruf werden alle „Produkt wieder verfügbar“-Benachrichtigungen aufgelistet, die für das Konto aktiviert sind. Er kann verwendet werden, um sie dem Kunden im Kundenkonto zur Ansicht zur Verfügung zu stellen. **Beispiel-Aufruf, der alle “Produkt wieder verfügbar”-Benachrichtigungen des aktuell eingeloggten Kundenkontos auflistet** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/account/backInStock/list ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "email": "", "productId": "12345" } ] } ``` ### POST account/backInStock/notify Mit diesem Aufruf wird für das eingeloggte Konto eine „Produkt wieder verfügbar“-Benachrichtigung eingerichtet. Sobald der Artikel wieder auf Lager ist, wird eine E-Mail an die angegebene Adresse verschickt. **Beispiel-Aufruf, der eine “Produkt wieder verfügbar”-Benachrichtigung für das Produkt mit der ID** `12345 `**anlegt. Die Benachrichtigung wird an die E-Mail-Adresse** ` `**versendet** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/account/backInStock/notify ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "", "productId": "12345" } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | -------------------------------------------------------------------------------------------------------------------- | | `email` | string | **Pflichtfeld**
    E-Mail-Adresse, an die die Benachrichtigung geschickt werden soll. | | `productId` | string | **Pflichtfeld**
    ID des Produkts, zu dem benachrichtigt werden soll. | | `storeId` | string | Optional. ID der Filiale, deren Lagerbestand überwacht werden soll. Ohne Angabe gilt das Standardlager des Subshops. | #### Fehlercodes | **Code** | **Beschreibung** | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `notLoggedIn` | Die Session ist in kein Konto eingeloggt. (fehlende / ungültige `x-session`) | | `notAllowed` | Das Feature ist in der Konfiguration deaktiviert. (Konfiguration des Feldes `content.inventory` unter `backInStock.allow`) | | `missingInventoryState` | Das Produkt hat keinen Lagerbestand. | | `entryExists` | Für dieselbe Kombination aus `productId`und `email` existiert bereits eine Benachrichtigung. | | `missingEmail` | `email` fehlt oder ist leer. | | `missingProductId` | `productId` fehlt oder ist leer. | | `invalidStoreId` | `storeId` ist keine gültige Filial-ID. | ### DELETE account/backInStock/notify Durch diesen Aufruf wird die für das eingeloggte Konto erstellte „Produkt wieder verfügbar“-Benachrichtigung gelöscht. **Beispiel-Aufruf, der eine “Produkt wieder verfügbar”-Benachrichtigung für das Produkt mit der ID** `12345 `**und der E-Mail-Adresse** ` `**wieder löscht** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} DELETE https://.de/api/v1/account/backInStock/notify ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "", "productId": "12345" } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ---------------------------------------------------------------------------------------- | | `email` | string | **Pflichtfeld**
    E-Mail-Adresse, für die die Benachrichtigung eingerichtet ist. | | `productId` | string | **Pflichtfeld**
    ID des Produkts, für das die Benachrichtigung gelöscht werden soll. | #### Fehlercodes | **Code** | **Beschreibung** | | ------------------ | ---------------------------------------------------------------------------- | | `notLoggedIn` | Die Session ist in kein Konto eingeloggt. (fehlende / ungültige `x-session`) | | `notAllowed` | Das Feature ist in der Konfiguration deaktiviert. | | `missingEmail` | `email` fehlt oder ist leer. | | `missingProductId` | `productId` fehlt oder ist leer. | *** ## Weitere Methoden für Kundendaten Mithilfe dieser Methoden wird das Kundenkonto um zentrale Self-Service-Funktionen ergänzt. Benutzer können ihre Bestellhistorie paginiert einsehen oder einzelne Bestellungen mitsamt Positionen, Adressen sowie Zahlungs- und Versanddetails gezielt abrufen. Zusätzlich kann man den öffentlichen Anzeigenamen für Produktbewertungen und die E-Mail-Adresse des Kontos ändern. Bei Bedarf ist eine nachgelagerte Bestätigung per Opt-in-Token erforderlich. Der komplette Lebenszyklus von Passwörtern wird abgedeckt: vom Ändern des Passworts im eingeloggten Zustand (inklusive optionaler Prüfung der aktuellen E-Mail-Adresse und/oder des bisherigen Passworts) bis hin zum Prozess „Passwort vergessen“ mit Wiederherstellungs-E-Mail und anschließendem Zurücksetzen über einen Opt-in-Token. ### GET account/order/list Mit diesem Aufruf wird die Bestellhistorie des aktuell eingeloggten Kundenkontos angezeigt. Er kann für die „Meine Bestellungen“-Seite im Kundenkonto genutzt werden. Über die Query-Parameter `page` und `size` lässt sich die Paginierung steuern (z. B. Seite 1 mit zehn Einträgen). So können Bestellungen seitenweise geladen und komfortabel angezeigt werden. Geliefert werden nur abgeschlossene Bestellungen (`paymentStatus = finished`) und keine gelöschten Bestellungen. Ist `general.order.orderHistoryDisplay` nicht auf `AllSubShops` gesetzt, enthält die Liste nur Bestellungen des aktuellen Subshops. Bei B2B-Unterkonten sieht ein Mitglied ohne das Recht `canViewFirmOrderHistory` nur die eigenen Bestellungen. **Beispiel-Aufruf, der die Bestellhistorie der Seite** `1 `**mit** `10 Einträgen `**des aktuell eingeloggten Kundenkontos anzeigt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/account/order/list?page=1&size=10 ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Query-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `page` | int | **Pflichtfeld**
    Gibt an, welche Seite der Bestellauflistung ausgegeben werden soll. Der Parameter muss größer oder gleich 1 sein. | | `size` | int | **Pflichtfeld**
    Gibt an, wie viele Bestellungen pro Seite angezeigt werden sollen. Erlaubt ist eine Anzahl zwischen 1 und 100. | | `order` | string | Sortierung (ID aus `general.order`), leer lassen für Standardsortierung. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items" : [ { "billAddress" : { "additionalInfo" : "", "addressType" : "", "businessFax" : "", "businessPhone" : "", "city" : "Nürnberg", "company" : "", "country" : "DE", "countryName" : "Deutschland", "custom" : null, "dateOfBirth" : "", "department" : "", "fax" : "", "firstName" : "Yvonne", "lastName" : "Kothmeier", "mobilePhone" : "", "phone" : "", "salutationCode" : "2", "salutationText" : "Frau", "state" : "", "street" : "Gutenstetterstraße 2", "streetNumber" : "", "taxId" : "", "titleCode" : "", "zip" : "90449" }, "customer" : { "accountId" : 88 }, "customerData" : {}, "freeFields" : { "agb.checked" : "true", "agb.merchantText" : "agb text here", "comment.text" : "" }, "general" : { "dateTime" : "2025-10-27T16:09:29Z", "orderId" : "4438", "sessionId" : "67f62f53c064541e51a51a086c9cc9e1a95cb49ff59eb719b11ac2e76742bc90", "shopId" : "demo", "shopLanguage" : "Deutsch", "subshopId" : "deutsch", "testMode" : false }, "order" : { "currencyIso" : "EUR", "currencySymbol" : "€", "defaultTaxRate" : "0.1900000", "delivererId" : "dhl", "delivererOrderText" : "DHL", "deliveryCost" : "0.00", "deliveryTaxRate" : "0.1900000", "fees" : { "currencyConversionRate" : 0, "feeOrgTotalOrder" : "59.99", "feeTotalOrder" : "59.99" }, "paymentId" : "bill", "paymentOrderText" : "Rechnung (offline)", "priceType" : "gross", "referer" : "", "subreferer" : "", "subtotal" : "59.99", "tax" : "9.58", "total" : "59.99", "totalCommission" : "0.00", "totalDiscount" : "0.00", "totalVoucher" : "0.00", "totalWeight" : 0 }, "orderList" : { "item" : [ { "basketId" : "342ac4f0c9c59e399c65", "discount" : "0.00", "extraFields" : {}, "freeFields" : { "categoryPath" : "Bekleidung" }, "isAutoBasket" : false, "isChangeable" : true, "isRemovable" : true, "isVisible" : true, "itemNumber" : "test", "name" : "Wollmantel mit Bindegürtel", "orgPrice" : "0.00", "price" : "59.99", "productId" : "155-03082", "quantity" : "1.00", "singleTotal" : "59.99", "taxId" : "19", "taxRate" : "0.1900000", "total" : "59.99", "variantId" : "", "variantSelection" : null, "weight" : 0 } ] }, "shippingAddress" : null, "store" : null } ], "page" : 1, "pageCount" : 4, "totalCount" : 37 } ``` `page` ist die aktuelle Seite, `pageCount` die Gesamtzahl der Seiten und `totalCount` die Gesamtzahl der Bestellungen. ### GET account/order/get Mit diesem Aufruf werden die Details einer konkreten Bestellung des aktuell eingeloggten Kundenkontos abgerufen, beispielsweise für die Detailseite der Bestellung. **Beispiel-Aufruf, der für das aktuell eingeloggte Kundenkonto die Details zur Bestellung mit der ID** `4869 `**abruft** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/account/order/get?orderId=4869 ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Query-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `orderId` | string | **Pflichtfeld**
    ID der Bestellung, die abgerufen werden soll. Wird als Query-Parameter übergeben, beispielsweise `?orderId=4869`. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "billAddress": null, "customer": { "accountId": 126 }, "customerData": {}, "deliveryStatus": { "trackingId": "00340434212840012345", "trackingUrl": "https://www.example.com/tracking?id=00340434212840012345" }, "freeFields": { "agb.checked": "true", "agb.merchantText": "agb text here", "comment.text": "" }, "general": { "dateTime": "2025-11-06T08:11:18Z", "orderId": "4869", "sessionId": "68343c298c1e6cd301d18d381a5ad70d73a872fbebfc2d0c4e4a7143214a8333", "shopId": "myshop", "shopLanguage": "Deutsch", "subshopId": "deutsch", "testMode": false }, "order": { "currencyIso": "EUR", "currencySymbol": "€", "defaultTaxRate": "0.1900000", "delivererId": "hermes", "delivererOrderText": "Hermes", "delivererType": "standard", "deliveryCost": "0.00", "deliveryTaxRate": "0.1900000", "fees": { "currencyConversionRate": 0, "feeOrgTotalOrder": "199.00", "feeTotalOrder": "199.00" }, "paymentId": "bill", "paymentOrderText": "Rechnung", "priceType": "gross", "referer": "", "subreferer": "", "subtotal": "199.00", "tax": "31.77", "total": "199.00", "totalCommission": "0.00", "totalDiscount": "0.00", "totalVoucher": "0.00", "totalWeight": 0 }, "orderList": { "item": [ { "basketId": "2014a8373f19d80b99e0", "discount": "0.00", "extraFields": {}, "freeFields": { "gravur1": "", "gravur2": "", "gravur3": "" }, "isAutoBasket": false, "isChangeable": true, "isRemovable": true, "isVisible": true, "itemNumber": "83-1783-44", "name": "Neuer Blazer 'Bethy'", "orgPrice": "0.00", "price": "199.00", "productId": "83-1783", "quantity": "1.00", "singleTotal": "199.00", "taxId": "1", "taxRate": "0.1900000", "total": "199.00", "variantId": "5", "variantSelection": [ { "attributeId": "Größe", "optionId": "44" } ], "weight": 0 } ] }, "shippingAddress": null, "store": null } ``` Das Feld `deliveryStatus` ist nur enthalten, wenn zu der Bestellung Versandstatusdaten vorliegen. Existiert die Bestellung nicht, gehört sie nicht zum eingeloggten Konto oder fehlt einem B2B-Unterkonto das Recht `canViewFirmOrderHistory`, liefert der Endpunkt `null`. ### POST account/displayName/update Mit diesem Aufruf lässt sich der öffentliche Anzeigename des aktuell eingeloggten Kundenkontos ändern. Dabei handelt es sich um den Namen, der bei Produktbewertungen neben den Rezensionen angezeigt wird. **Beispiel-Aufruf, der den öffentlichen Anzeigenamen des aktuell eingeloggten Benutzerkontos auf** `Name `**ändert** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/account/displayName/update ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "displayName": "Name" } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ---------------------------------------------------- | | `displayName` | string | **Pflichtfeld** Neuer Anzeigename für Bewertungen. | #### Beispiel-Response ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Fehlercodes | **Code** | **Beschreibung** | | -------------------- | ---------------------------------- | | `notLoggedIn` | Es ist kein Benutzer eingeloggt. | | `missingDisplayName` | `displayName` fehlt oder ist leer. | ### POST account/email/update Mit dem folgenden Aufruf kann die E-Mail-Adresse des eingeloggten Kontos geändert werden. Je nach Konfiguration wird anschließend möglicherweise eine E-Mail-Verifizierung ausgelöst. **Beispiel-Aufruf, der die E-Mail-Adresse für das aktuell eingeloggte Benutzerkonto auf** `neue.adresse@example.com `**ändert** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/account/email/update ``` #### Beispiel-Request ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "neue.adresse@example.com" } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------------------- | | `email` | string | **Pflichtfeld**
    Neue E-Mail-Adresse. | #### Fehlercodes | **Code** | **Beschreibung** | | ---------------------- | --------------------------------------------------------------------- | | `emailCheckFailed` | Die angegebene E-Mail hat ein ungültiges Format. | | `accountAlreadyExists` | Es existiert bereits ein Account mit dieser E-Mail-Adresse. | | `updateFailed` | Die E-Mail-Adresse konnte nicht gespeichert werden (Datenbankfehler). | Nach erfolgreicher Änderung werden alle Autologin-Token des Kontos gelöscht, sodass gespeicherte „Angemeldet bleiben“-Anmeldungen auf allen Geräten verfallen. Zusätzlich wird ein Opt-In-Token für `account/email/verify` erzeugt und per E-Mail versendet. ### POST account/email/verify Mit dem folgenden Aufruf wird die E-Mail-Adresse mithilfe des Opt-In-Tokens aus der Bestätigungs-E-Mail bestätigt. **Beispiel-Aufruf, der die E-Mail-Adresse mithilfe des** `Opt-In-Token `**verifiziert** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/account/email/verify ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "otok": "" } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ---------------------------------------------------------------------------------------------------------------- | | `otok` | string | Opt-In Token aus der Bestätigungsmail. Kann ein Pflichtfeld oder optional sein. Mehr Infos siehe Hinweis oben. | #### Beispiel-Response ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Fehlercodes | **Code** | **Beschreibung** | | ------------------ | ------------------------------------------- | | `actionNotAllowed` | Der übermittelte Opt-In-Token ist ungültig. | ### POST account/password/change Mit diesem Aufruf wird das Passwort des aktuell eingeloggten Kontos geändert. Je nach Shop-Konfiguration kann die Eingabe des aktuellen Passworts erforderlich sein und/oder eine E-Mail-Bestätigung ausgelöst werden. **Beispiel-Aufruf, um für das aktuelle Benutzerkonto ein neues Passwort (**``**) zu setzen** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/account/password/change ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "newPassword": "", "newPasswordRepeat": "" } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `newPassword` | string | **Pflichtfeld**
    Das gewünschte neue Passwort für das Benutzerkonto. | | `newPasswordRepeat` | string | **Pflichtfeld**
    Wiederholung des neuen Passworts. Muss exakt mit `newPassword` übereinstimmen. | | `email` | string | Die E-Mail-Adresse des Kontos, für das das Passwort geändert werden soll. Nur erforderlich, wenn in der Konfiguration vorgegeben. | | `passwordAuth` | string | Nur erforderlich, wenn in der Konfiguration vorgegeben. | #### Beispiel-Response ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Fehlercodes | **Code** | **Beschreibung** | | --------------------- | --------------------------------------------------------------------------------------------------------- | | `notLoggedIn` | Die Session ist nicht eingeloggt. (fehlende / ungültige `x-session`) | | `emailMismatch` | Die angegebene E-Mail-Adresse stimmt nicht mit dem Konto überein. | | `missingEmail` | Die E-Mail-Prüfung wurde in der Konfiguration aktiviert, aber `email` fehlt im Request. | | `failedPasswordAuth` | Das eingegebene Passwort ist falsch. | | `missingPasswordAuth` | Prüfung des aktuellen Passworts ist in der Konfiguration aktiviert, aber `passwordAuth` fehlt im Request. | | `passwordCheckFailed` | Das neue Passwort erfüllt die Mindeststandards nicht. (z.B. Länge / Komplexität) | | `getPasswordMismatch` | `newPassword` und `newPasswordRepeat` stimmen nicht überein. | | `missingPassword` | `newPassword` fehlt oder ist leer. | ### POST account/password/forgotten Mit dem folgenden Aufruf wird die Passwort-Zurücksetzung für die angegebene E-Mail-Adresse gestartet (es wird eine E-Mail mit weiteren Informationen zum Vorgehen versendet). **Beispiel-Aufruf, der den “Passwort vergessen”-Link an die E-Mail-Adresse** `kunde@example.com `**sendet** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/account/password/forgotten ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "kunde@example.com" } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------------------------- | | `email` | string | **Pflichtfeld**
    E-Mail-Adresse des Kontos. | #### Fehlercodes | **Code** | **Beschreibung** | | ------------------------ | ------------------------------------------------------------ | | `emailCheckFailed` | Die angegebene E-Mail-Adresse hat ein ungültiges Format. | | `passwordRecoveryFailed` | Für die angegebene E-Mail-Adresse wurde kein Konto gefunden. | ### POST account/password/reset Mit folgendem Aufruf kann das Passwort mithilfe des Opt-In-Tokens aus der „Passwort vergessen“-E-Mail zurückgesetzt werden: **Beispiel-Aufruf, der die Passwortrücksetzung für das Kundenkonto mit der E-Mail-Adresse** `kundenkonto@example.com `**bestätigt und als neues Passwort** `password `**setzt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/account/password/reset ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "newPassword": "password", "newPasswordRepeat": "password", "email": "kundenkonto@example.com", "otok": "AZ3XHlWGe4E98D4fsJrPhWclSgBBQwAAAAA.ZKgwbjF-IDLuaakADfazRmAWTmjdH-A9W92JtZnPVPQ" } ``` #### Beispiel-Response ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `newPassword` | string | **Pflichtfeld**
    Das gewünschte neue Passwort. | | `newPasswordRepeat` | string | **Pflichtfeld**
    Wiederholung des neuen Passworts. Muss exakt mit `newPassword` übereinstimmen, sonst kommt der Fehler `getPasswordMismatch`. | | `otok` | string | **Pflichtfeld**
    Opt-In-Token aus der “Passwort vergessen” E-Mail. | | `email` | string | Nur erforderlich, wenn die Prüfung der E-Mail in der Konfiguration aktiviert ist. | #### Fehlercodes | **Code** | **Beschreibung** | | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `notLoggedIn` | Es liegt weder ein gültiger, noch nicht eingelöster Opt-In-Token für `ResetPassword` vor, noch ist die Session in ein Konto eingeloggt. | | `emailMismatch` | Die angegebene E-Mail-Adresse stimmt nicht mit dem Konto überein. | | `missingEmail` | E-Mail-Prüfung ist in der Konfiguration aktiviert, aber `email` wurde nicht als Parameter übermittelt. | | `passwordCheckFailed` | Das neue Passwort erfüllt die Richtlinien nicht. | # Storefront API Lagerbestand Source: https://dokumentation.websale.de/schnittstellen/storefront-api/storefront-api-lagerbestand Verfügbarkeit, Lagerbestand und verbleibende Reservierungsdauer von Produkten und Varianten über die Storefront API für das Frontend abrufen. Die Verfügbarkeit-&-Lager API ergänzt Katalogdaten um Bestands- und Verfügbarkeitsinformationen. Damit lässt sich im Frontend anzeigen, ob ein Produkt und dessen Variante aktuell verfügbar ist oder als ausverkauft gilt, und entsprechende Hinweise können direkt an Produktlisten oder auf Produktdetailseiten ausgegeben werden. Darüber hinaus kann die verbleibende Reservierungsdauer für eine Warenkorb-Position eines Artikels abgefragt werden. Für die Anfragen muss zwingend eine `x-session` mitgegeben werden. Mehr dazu [hier](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling). *** ## Unterstützte Methoden Angabe aller Unterstützten Methoden: | **Befehl** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | --------------------------------------------- | --------------------------- | --------------------- | ------------------- | ------------------- | ------------------- | | Lagerbestand eines Produkts anzeigen | `inventory/load` | | | | | | Reservierung einer Warenkorbposition anzeigen | `inventory/loadReservation` | | | | | ## Methoden für den Lagerbestand Mithilfe dieser Methoden können Bestandsinformationen zu Produkten sowie Details zu laufenden Reservierungen im Warenkorb abgerufen werden. Darüber hinaus ermöglichen sie Verfügbarkeits- und Lieferhinweise und zeigen die verbleibende Reservierungszeit einer Position an. ### GET inventory/load Mit diesem Aufruf kann der aktuelle Lagerstatus eines Produkts (Menge, Zustand, Hinweise) abgerufen werden. Die Informationen können zur Anzeige von Lagerbeständen oder Lieferhinweisen verwendet werden. **Beispiel-Aufruf des Produkts mit der Produkt-ID** `191-98487` ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/inventory/load?productId=191-98487 ``` #### Query-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | -------------------------------------------------------------------------- | | `productId` | string | **Pflichtfeld**
    ID des Produkts, dessen Inventar geladen werden soll. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "active": true, "amount": 33, "deliveryText": "Nur noch wenige Stück auf Lager", "messageLimit": 5, "soldOut": false, "splitDelivery": false, "state": "yellow" } ``` | **Feld** | **Typ** | **Beschreibung** | | ------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `state` | string | Ampelstatus: `green`, `yellow` oder `red`. | | `deliveryText` | string | Lieferhinweis zum Ampelstatus, global oder je Produkt konfiguriert. | | `soldOut` | bool | `true`, wenn der Status `red` ohne Nachbestellung ist. | | `messageLimit` | int | Meldebestand des Produkts, ersatzweise der globale Wert. | | `splitDelivery` | bool | `true`, wenn Teillieferung gilt. Nur dann sind `deliveryTextInStock` und `deliveryTextOutOfStock` vorhanden. | | `amount` | int | **Optional**
    Verfügbare Menge. Nur bei dynamischer Bestandsführung vorhanden, nie bei fest gesetztem Ampelstatus. Negative Werte werden als `0` ausgegeben. | | `active` | bool | **Optional**
    Nur vorhanden, wenn die Lagerhaltung für das Produkt konfiguriert ist. | | `deliveryTextInStock` | string | **Optional**
    Lieferhinweis für den vorrätigen Teil, nur bei `splitDelivery: true`. | | `deliveryTextOutOfStock` | string | **Optional**
    Lieferhinweis für den nicht vorrätigen Teil, nur bei `splitDelivery: true`. | | `amountInStock` | int | **Optional**
    Vorrätiger Anteil der reservierten Menge, nur bei Teillieferung im roten Bereich. | | `amountNotInStock` | int | **Optional**
    Nicht vorrätiger Anteil der reservierten Menge, nur bei Teillieferung im roten Bereich. | ### GET inventory/loadReservation Mit diesem Aufruf kann man die aktuelle Reservierungsdauer für eine bestimmte Warenkorb-Position abrufen (Restlaufzeit und Ablaufzeitpunkt). Mithilfe dieser Information können beispielsweise Hinweise zum Ablauf gesteuert werden. **Beispiel-Aufruf einer Reservierung mit der Warenkorb-Positions-ID** `f28e67292c99759e5fb9` ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/inventory/loadReservation?basketItemId=f28e67292c99759e5fb9 ``` #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Query-Parameter | **Parameter** | **Typ** | **Beschreibung** | | -------------- | ------- | ---------------------------------------------------------------------------------- | | `basketItemId` | string | **Pflichtfeld**
    ID der Warenkorb-Position, deren Reservierung abgefragt wird. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "duration": 531, "reservedUntil": "2025-11-03T11:08:40Z" } ``` # Storefront API Merkliste Source: https://dokumentation.websale.de/schnittstellen/storefront-api/storefront-api-merkliste Merklisten in der Storefront über die Storefront API anlegen, umbenennen, löschen sowie einzelne Produkte gezielt hinzufügen und entfernen. Mithilfe der Storefront-API für Merklisten können Produkte gespeichert, verwaltet und später schnell wiedergefunden werden. Sie bietet Endpunkte zum Anlegen, Umbenennen und Löschen von Merklisten sowie zum Hinzufügen und Entfernen einzelner Produkte. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | ----------------------------------------------------------------------------- | --------------------------------- | --------------------- | --------------------- | --------------------- | --------------------- | | Eine Merkliste abrufen. | `watchList/load` | | | | | | Alle Merklisten abrufen. | `watchList/list` | | | | | | Position eines Produktes auf der Merkliste abrufen. | `watchList/getItemId` | | | | | | Prüfung, ob ein Produkt sich bereits auf einer bestimmten Merkliste befindet. | `watchList/checkHasProduct` | | | | | | Prüfung, in wie vielen Merklisten ein bestimmtes Produkt enthalten sind. | `watchList/countListsWithProduct` | | | | | | Eine neue Merkliste erstellen. | `watchList/add` | | | | | | Ein oder mehrere Produkte zu einer oder mehreren Merkliste(n) hinzufügen. | `watchList/addItem` | | | | | | Ein Produkt aus einer Merkliste löschen. | `watchList/deleteItem` | | | | | | Den Namen einer Merkliste ändern. | `watchList/rename` | | | | | | Eine Merkliste dauerhaft löschen. | `watchList/delete` | | | | | ## Methoden für die Merkliste Mit diesen Methoden können Merklisten im Kundenkonto verwaltet werden: Sie laden entweder einzelne Merklisten inklusive der gespeicherten Produkte oder listen alle zum eingeloggten Nutzer gehörenden Merklisten auf. Darüber hinaus können Sie prüfen, ob bzw. wie oft ein Produkt auf Merklisten steht, neue Merklisten anlegen, Produkte (einzeln oder gesammelt) zu einer oder mehreren Merklisten hinzufügen oder wieder entfernen sowie komplette Merklisten umbenennen oder löschen. Alle Endpunkte akzeptieren ausschließlich die jeweils dokumentierten Parameter. Ein nicht dokumentierter Parameter führt zu HTTP 400 mit einer Fehlerliste im Body. ### watchList/load Mit dem folgenden Aufruf wird eine Merkliste inklusive aller gespeicherten Artikel geladen. Er kann verwendet werden, um Merklisten samt Produktdaten weiterzuverarbeiten. **Beispiel-Aufruf, der die Merkliste mit der ID** `watchlist_132_cf76964799db4ce `**anzeigt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/watchList/load?watchListId=watchlist_132_cf76964799db4ce ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Query-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------------------------------------- | | `watchListId` | string | **Pflichtfeld**
    ID der Merkliste, die geladen werden soll. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id": "watchlist_132_cf76964799db4ce", "watchListName": "testlist67", "items": [ { "id": "6d90bbb6c33294ddcd91", "freeFields": {}, "product": { "id": "146-78608", "itemNumber": "67", "name": "Plushie", "price": 6.7, "custom": { "image": {} }, "isSetProduct": true, "setProducts": [ { "id": "147-15732", "quantityFactor": 1, "usePrice": true, "hidden": false, "fixQuantity": false } ], "taxRateId": "19", "new": true, "timestampCreatedAt": "2025-11-04T09:27:18.000Z", "timestampUpdatedAt": "2025-11-10T07:52:20.000Z" } } ] } ``` Hinweis: Einträge, deren Produkt im aktuellen Subshop nicht geladen werden kann (beispielsweise gelöscht oder nicht freigeschaltet), werden in `items` übersprungen. Die Merkliste selbst bleibt unverändert. ### GET watchList/list Mit folgendem Aufruf werden alle Merklisten des aktuell eingeloggten Kundenkontos angezeigt. Er kann zum Anzeigen, Auswählen oder Umschalten zwischen mehreren Merklisten eines Nutzers verwendet werden. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/watchList/list ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} [ { "watchListId": "watchlist_37_default", "watchListName": "Merkliste" }, { "watchListId": "watchlist_37_basket", "watchListName": "Für später gespeichert" } ] ``` ### GET watchList/getItemId Der folgende Aufruf liefert die Positions-ID eines bestimmten Produkts innerhalb einer konkreten Merkliste. Die Positions-ID ist dieselbe wie die ID eines Eintrags bei `watchList/load`. **Beispiel Aufruf, der die Position des Produkts mit der ID** `146-78608 `**aus der Merkliste mit der ID** `watchlist_132_cf76964799db4ce `**zurückgibt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/watchList/getItemId?watchListId=watchlist_132_cf76964799db4ce&productId=146-78608 ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Query-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------ | | `watchListId` | string | **Pflichtfeld**
    ID der Merkliste, in der sich das Produkt befindet. | | `productId` | string | **Pflichtfeld**
    ID des Produktes in der Watchlist. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "itemId": "6d90bbb6c33294ddcd91" } ``` Liegt das Produkt nicht auf der angegebenen Merkliste, ist `itemId` `null`. ### GET watchList/checkHasProduct Mit folgendem Aufruf lässt sich prüfen, ob ein bestimmtes Produkt bereits auf einer konkreten Merkliste liegt. Er kann verwendet werden, um Wunschlisten-Buttons umzuschalten oder Doppelanlagen zu verhindern. **Beispiel-Aufruf, ob das Produkt mit der ID** `146-78608 `**auf der Merkliste mit der ID** `watchlist_132_cf76964799db4ce `**vorhanden ist** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/watchList/checkHasProduct?watchListId=watchlist_132_cf76964799db4ce&productId=146-78608 ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Query-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `watchListId` | string | **Pflichtfeld** ID der Merkliste, die durchsucht werden soll. | | `productId` | string | Optional. ID des Produktes, nach dem gesucht werden soll. Wird der Parameter weggelassen, antwortet der Endpunkt mit `{"isOnList": false}` statt mit einem Fehler. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "isOnList": true } ``` #### HTTP-Status | **Status** | **Bedeutung** | | ---------- | ------------------------------------------------------------------------------------ | | `400` | Kein oder ungültiger `x-session`-Header, oder unbekannter Query-Parameter übergeben. | | `404` | Die angegebene `watchListId` gehört nicht zu den Merklisten der aktuellen Session. | ### GET watchList/countListsWithProduct Der folgende Aufruf zählt, in wie vielen Merklisten das angegebene Produkt gespeichert ist. Er kann auf Produkt- und Kategorieseiten verwendet werden, um zu signalisieren, dass das Produkt begehrt ist, und kann beispielsweise mit dem Hinweis „Auf xxx Merklisten gespeichert” angezeigt werden. **Beispiel-Aufruf, der zählt, wie oft sich das Produkt mit der ID** `146-78608 `**auf Merklisten befindet** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/watchList/countListsWithProduct?productId=146-78608 ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Query-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | --------------------------------------------------------------------------------- | | `productId` | string | **Pflichtfeld** ID des Produktes, nach dem Merklisten durchsucht werden sollen. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "count": 2 } ``` ### POST watchList/add Mit dem folgenden Aufruf wird eine neue Merkliste für den aktuell angemeldeten Nutzer angelegt. **Beispiel-Aufruf, der eine neue Merkliste mit dem Namen** `“Please, I need this” `**anlegt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/watchList/add ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "watchListName": "Please, I need this" } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld** ID der aktuellen Session. Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | --------------- | ------- | -------------------------------------------------------- | | `watchListName` | string | **Pflichtfeld**
    Name der zu erstellenden Watchlist. | #### Beispiel-Response ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Fehlercodes | **Code** | **Beschreibung** | | ---------------------- | ------------------------------------------ | | `notLoggedIn` | Der Nutzer ist nicht eingeloggt. | | `missingWatchListName` | `watchListName` fehlt oder ist leer. | | `missingService` | Der Merklisten-Dienst ist nicht verfügbar. | ### PUT watchList/addItem Mit folgendem Aufruf können ein oder mehrere Produkte zu einer oder mehreren Merklisten hinzugefügt werden. Er kann für Merklisten-Buttons auf Produkt-/Listing-Seiten sowie für Bulk-Aktionen verwendet werden. **Beispiel-Aufruf, der die Produkte mit der ID** `147-15732 `**und** `146-78608 `**zu der Merkliste mit der ID** `watchlist_132_cf76964799db4ce `**hinzufügt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} PUT https://.de/api/v1/watchList/addItem ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "watchListIds": { "watchlist_132_cf76964799db4ce": "watchlist_132_cf76964799db4ce" }, "multiProducts": { "147-15732": {}, "146-78608": {} } } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | --------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `watchListIds` | object | **Pflichtfeld** Liste der Ziel-Merklisten. Schlüssel und Wert sind die Watchlist-IDs. Es muss mindestens eine ID angegeben werden. | | `productId` | string | Ein Produkt, das hinzugefügt werden soll. **Pflichtfeld**, wenn `multiproducts`nicht übergeben wird. | | `multiProducts` | object | Fügt mehrere Produkte in einem Aufruf hinzu. Schlüssel sind die Produkt-IDs. Der Wert ist ein Objekt, das optional `freeFields` für dieses Produkt enthält. Ein leeres Objekt genügt. **Pflichtfeld**, wenn `productId` nicht übergeben wird. | | `freeFields` | object | Optional. Freie Zusatzdaten zum Produkt. Wird nur zusammen mit `productId` ausgewertet. Bei `multiProducts` wird dieses Feld ignoriert, dort werden die Zusatzdaten je Produkt aus dem Wert des Eintrags gelesen, beispielsweise `"multiProducts": { "147-15732": { "freeFields": { "farbe": "rot" } } }`. | #### Beispiel-Response ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Fehlercodes | **Code** | **Beschreibung** | | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | `invalidProductId` | Das angefragte Produkt existiert nicht, oder es wurde eine Variantenkennung (`.`) an ein Produkt ohne Varianten angehängt. | | `invalidVariantId` | Das Produkt wurde gefunden, aber die zugehörige Variante nicht. | | `watchListNotFound` | Die angegebene Merkliste existiert nicht. | | `missingProductId` | Es wurde weder `productId` noch `multiProducts` übergeben. | | `missingService` | Der Merklisten-Dienst ist nicht verfügbar (Speicherdienst nicht erreichbar). | ### PUT watchList/rename Mit folgendem Aufruf wird eine bestehende Merkliste umbenannt. **Beispiel-Aufruf, der die Merkliste mit der ID** `watchlist_132_cf76964799db4ce `**in** `“Liste 67” `**umbenennt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} PUT https://.de/api/v1/watchList/rename ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "watchListId": "watchlist_132_cf76964799db4ce", "newWatchListName": "Liste 67" } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------------ | ------- | --------------------------------------------------- | | `watchListId` | string | **Pflichtfeld** ID der umzubenennenden Merkliste. | | `newWatchListName` | string | **Pflichtfeld** Neuer Name für die Merkliste. | #### Beispiel-Response ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Fehlercodes | **Code** | **Beschreibung** | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | `missingWatchListId` | `watchListId` fehlt oder ist leer. | | `missingWatchListName` | `newWatchListName` fehlt oder ist leer. | | `watchListNotFound` | Die Merkliste mit der angegebenen ID existiert nicht. | | `notChangeable` | Die Merkliste darf nicht umbenannt werden (gilt für die automatisch erstellten Standardmerklisten `…_default` und `…_basket`). | | `missingService` | Der Merklisten-Dienst ist nicht verfügbar. | ### DELETE watchList/deleteItem Mit diesem Aufruf wird ein bestimmtes Produkt aus einer Merkliste entfernt. **Beispiel-Aufruf, der das Produkt mit der** `watchListItemId 6d90bbb6c33294ddcd91`**(diese ID erhält man über den Aufruf von** `watchList/getItemId`**) von der Wunschliste mit der ID** `watchlist_132_cf76964799db4ce `**entfernt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} DELETE https://.de/api/v1/watchList/deleteItem ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "watchListId": "watchlist_132_cf76964799db4ce", "watchListItemId": "6d90bbb6c33294ddcd91" } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ----------------- | ------- | ----------------------------------------------------------------------------- | | `watchListId` | string | **Pflichtfeld** ID der Watchlist, aus der der Eintrag entfernt werden soll. | | `watchListItemId` | string | **Pflichtfeld** Positions-ID des zu entfernenden Produktes. | #### Beispiel-Response ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Fehlercodes | **Code** | **Beschreibung** | | -------------------- | ---------------------------------------------------------- | | `missingWatchListId` | `watchListId` fehlt oder ist leer. | | `missingItemId` | `watchListItemId` fehlt oder ist leer. | | `invalidItemId` | Es existiert kein Eintrag mit dieser ID auf der Merkliste. | | `watchListNotFound` | Die Merkliste mit der angegebenen ID existiert nicht. | | `missingService` | Der Merklisten-Dienst ist nicht verfügbar. | ### DELETE watchList/delete Mit dem folgenden Aufruf wird eine bestehende Merkliste dauerhaft gelöscht. **Beispiel-Aufruf, der die Merkliste mit der ID** `watchlist_132_cf76964799db4ce `**dauerhaft entfernt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} DELETE https://.de/api/v1/watchList/delete ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "watchListId": "watchlist_132_cf76964799db4ce" } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------- | | `watchListId` | string | **Pflichtfeld** ID der zu löschenden Merkliste. | #### Beispiel-Response ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {} ``` #### Fehlercodes | **Parameter** | **Beschreibung** | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `watchListNotFound` | Die angegebene Merkliste existiert nicht. | | `notChangeable` | Die Merkliste darf nicht gelöscht werden (gilt für die automatisch erstellten Standardmerklisten `…_default` und `…_basket`). | | `missingService` | Der Merklisten-Dienst ist nicht verfügbar. | # Storefront API Newsletter Source: https://dokumentation.websale.de/schnittstellen/storefront-api/storefront-api-newsletter Newsletter-Anmeldungen und -Abmeldungen für eingeloggte Kunden und anonyme Besucher über die Storefront API als Opt-in/Opt-out abbilden. Die Newsletter API dient zur Integration von Newsletter-Anmeldungen und -Abmeldungen für das WEBSALE Newsletter-Modul in der Storefront. Sie kann sowohl für eingeloggte Kunden als auch für anonyme Besucher verwendet werden und bildet die üblichen Opt-in/Opt-out-Vorgänge im Frontend ab. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | ------------------------------------------------------- | ------------------------------- | --------------------- | ------------------- | --------------------- | ------------------- | | Liste der im Shop konfigurierten Newsletter-Zielgruppen | `newsletter/targetGroups` | | | | | | Erstellt ein neues Newsletter-Abo. | `newsletter/subscribe` | | | | | | Bestätigt ein neues Newsletter-Abo. | `newsletter/subscribeConfirm` | | | | | | Abmeldung vom Newsletter. | `newsletter/unsubscribe` | | | | | | Bestätigung der Abmeldung vom Newsletter. | `newsletter/unsubscribeConfirm` | | | | | | Setzt eine E-Mail-Adresse auf die Sperrliste. | `newsletter/blacklist` | | | | | | Bestätigt die Sperre der E-Mail-Adresse. | `newsletter/blacklistConfirm` | | | | | ## Methoden für den Newsletter Mithilfe dieser Methoden wird das komplette Newsletter-Management im Shop gesteuert: Sie lesen die konfigurierten Zielgruppen aus und ermöglichen das Anlegen, Bestätigen (Double-Opt-In) und Beenden von Newsletter-Abos – optional je Zielgruppe. Zusätzlich können E-Mail-Adressen dauerhaft über eine Blacklist vom Versand ausgeschlossen werden, was ebenfalls per Bestätigungslink abgesichert ist. Validierungen und typische Fehlerfälle (z. B. fehlende Pflichtfelder, ungültige Zielgruppen oder falsche bzw. abgelaufene Opt-in-Tokens) werden dabei über definierte Fehlercodes zurückgemeldet. ### GET newsletter/targetGroups Der folgende Aufruf liefert alle im Shop konfigurierten Newsletter-Zielgruppen. Er kann verwendet werden, um beim Newsletter-Anmeldeformular oder auf Profil-/Einstellungsseiten auswählbare Zielgruppen anzuzeigen. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/newsletter/targetGroups ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------- | | -- | -- | Keine zusätzlichen Parameter. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "deactivated": false, "id": 1, "name": "foo" }, { "deactivated": false, "id": 2, "name": "asdf" } ] } ``` ## POST newsletter/subscribe Mit folgendem Aufruf wird für eine E-Mail-Adresse ein Newsletter-Abo angelegt und optional Zielgruppen zugeordnet. Bei aktiviertem Double-Opt-In-Verfahren wird zuerst eine Bestätigungs-E-Mail verschickt. Das Abonnement ist erst nach Bestätigung aktiv. Es ist für Anmeldeformulare mit Auswahl von Zielgruppen und Erfassung zusätzlicher Felder verwendbar. **Beispiel-Aufruf, der ein Newsletter-Abo für das Kundenkonto mit der E-Mail-Adresse** `maria.musterfrau@example.com `**und die Newslettergruppen** `1 `**und** `2 `**anlegt. Als optionale Zusatzinformationen wird der Vor- und Nachname mitgegeben** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/newsletter/subscribe ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "maria.musterfrau@example.com", "targetGroupId": { "1": "1", "2": "2" }, "firstName": "Maria", "lastName": "Musterfrau" } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `email` | string | **Pflichtfeld**
    E-Mail-Adresse, die den Newsletter abonnieren soll. | | `targetGroupId` | object | Zielgruppen, die dieses Abo erhalten soll. Schlüssel sind die Zielgruppen-IDs. Die gültigen IDs erhält man über `GET newsletter/targetGroups`. | | weitere Felder | string | Optional. Zusätzliche Angaben zum Abonnenten werden auf oberster Ebene des Request-Bodys übergeben, beispielsweise `firstName` und `lastName`. Namen und Formate müssen den unter `newsletter.fields` konfigurierten Feldern entsprechen. | #### Fehlercodes | **Code** | **Beschreibung** | | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `missingField` | Ein als Pflichtfeld markiertes Feld fehlt. | | `invalidField` | Ein Wert entspricht nicht den Validierungsregeln in der Konfiguration. Mehr dazu: [Validierungs- und Prüfservices](/konfiguration/validierungs-und-prufservices) | | `invalidTargetGroupId` | Eine angegebene Zielgruppen-ID existiert nicht. | | `deactivatedTargetGroup` | Eine angegebene Zielgruppe ist deaktiviert oder nimmt keine neuen Abonnenten auf. | | `emailCheckFailed` | Die angegebene E-Mail-Adresse ist ungültig. | ### POST newsletter/subscribeConfirm Mit dem folgenden Aufruf kann ein zuvor über „Newsletter/Subscribe” gestartetes Newsletter-Abo per Opt-In-Token bestätigt werden. Dadurch wird das Abo für die angegebene E-Mail-Adresse aktiviert. Er ist für das Handling in der Double-Opt-In-E-Mail verwendbar. **Beispiel-Aufruf, der mithilfe des Bestätigungscodes aus der E-Mail das Newsletter-Abo bestätigt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/newsletter/subscribeConfirm ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "otok": "" } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | -------------------------------------------------------------- | | `otok` | string | **Pflichtfeld**
    Opt-In-Token aus der Bestätigungs-E-Mail. | #### Fehlercodes | **Code** | **Beschreibung** | | ------------------ | --------------------------------------------------------------- | | `actionNotAllowed` | Der Opt-In-Token ist für diese Aktion ungültig oder abgelaufen. | | `internalError` | Interner Fehler; kann nur von WEBSALE behoben werden. | ### POST newsletter/unsubscribe Mit folgendem Aufruf kann man sich vom Newsletter abmelden – auf Wunsch auch nur aus bestimmten Zielgruppen. Bei aktiviertem Double-Opt-In-Verfahren ist unter Umständen eine zusätzliche Bestätigungs-E-Mail erforderlich. Dies ist beispielsweise für ein Abmeldeformular oder einen Abmelde-Link nutzbar. **Beispiel-Aufruf, der das Kundenkonto mit der E-Mail** `maria.musterfrau@example.com `**von den Newsletter-Zielgruppen** `1 `**und** `2 `**abmeldet** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/newsletter/unsubscribe ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "maria.musterfrau@example.com", "targetGroupId": { "1": "1", "2": "2" } } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | --------------- | ------- | ---------------------------------------------------------------------------------- | | `email` | string | **Pflichtfeld**
    E-Mail-Adresse, die abgemeldet werden soll. | | `targetGroupId` | object | Zielgruppen, aus denen abgemeldet werden soll. Schlüssel sind die Zielgruppen-IDs. | #### Fehlercodes | **Code** | **Beschreibung** | | -------------- | -------------------------------------------------------------------------------------------------------- | | `missingEmail` | Die E-Mail-Adresse fehlt oder ist leer. | | `missingField` | Es wurde keine Zielgruppe übergeben. | | `invalidField` | Die übergebenen Zielgruppen haben nicht das erwartete Format oder enthalten keine gültige numerische ID. | ### POST newsletter/unsubscribeConfirm Mit dem folgenden Aufruf kann eine per Opt-In-Token aus der Bestätigungs-E-Mail erfolgte Newsletter-Abmeldung bestätigt und endgültig abgeschlossen werden. Er ist für das Handling der Abmelde-E-Mail verwendbar. **Beispiel-Aufruf, der mithilfe des Bestätigungscodes aus der E-Mail das Newsletter-Abo beendet** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/newsletter/unsubscribeConfirm ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "otok": "" } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | -------------------------------------------------------------- | | otok | string | **Pflichtfeld**
    Opt-In-Token aus der Bestätigungs-E-Mail. | #### Fehlercodes | **Code** | **Beschreibung** | | ------------------ | --------------------------------------------------------------- | | `actionNotAllowed` | Der Opt-In-Token ist für diese Aktion ungültig oder abgelaufen. | | `internalError` | Interner Fehler; kann nur von WEBSALE behoben werden. | ### POST newsletter/blacklist Mit dem folgenden Aufruf wird eine E-Mail-Adresse auf die Sperrliste gesetzt, sodass an diese Adresse keine Newsletter mehr versendet werden. Die Sperre kann durch erneutes Abonnieren wieder aufgehoben werden. Dies ist beispielsweise für Opt-Out-Funktionen wie „Keine Newsletter mehr erhalten“ verwendbar. Ist in der Shop-Konfiguration `newsletter.blacklistSelfDoubleOptIn` aktiv, wird zunächst eine Bestätigungs-E-Mail verschickt. Die Sperre greift erst nach `POST newsletter/blacklistConfirm`. Ist die Einstellung nicht aktiv, wird die Adresse sofort gesperrt. **Beispiel-Aufruf, der die E-Mail-Adresse** `maria.musterfrau@websale.de `**auf die Sperrliste setzt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/newsletter/blacklist ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "email": "maria.musterfrau@websale.de" } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ----------------------------------------------------- | | `email` | string | **Pflichtfeld**
    Die zu sperrende E-Mail-Adresse. | #### Fehlercodes | **Code** | **Beschreibung** | | ------------------ | ------------------------------------------- | | `missingField` | Die E-Mail-Adresse fehlt oder ist leer. | | `emailCheckFailed` | Die angegebene E-Mail-Adresse ist ungültig. | ### POST newsletter/blacklistConfirm Folgender Aufruf bestätigt die zuvor angeforderte Sperre (auf die Sperrliste setzen) einer E-Mail-Adresse per Opt-In-Token aus der Bestätigungs-Mail. Verwendbar für den Abschluss des Sperrlisten-Prozesses nach Klick auf den Link aus der E-Mail. **Beispiel-Aufruf, der mithilfe des Bestätigungscodes aus der E-Mail die E-Mail-Adresse auf die Sperrliste setzt** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/newsletter/blacklistConfirm ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "otok": "" } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | -------------------------------------------------------------- | | otok | string | **Pflichtfeld**
    Opt-In-Token aus der Bestätigungs-E-Mail. | #### Fehlercodes | **Code** | **Beschreibung** | | ------------------ | --------------------------------------------------------------- | | `actionNotAllowed` | Der Opt-In-Token ist für diese Aktion ungültig oder abgelaufen. | # Storefront API Optionen Source: https://dokumentation.websale.de/schnittstellen/storefront-api/storefront-api-optionen Werte von Template-Optionen über die Storefront-API auslesen – global oder pro Konfigurationsknoten. Die Optionen-API liefert die Werte von [Template-Optionen](/frontend/referenz/optionen) über die Storefront-API, analog zum Template-Modul [\$wsOptions](/frontend/referenz/module/ws-options-template-optionen). So lassen sich im Template definierte und im Admin-Interface gepflegte Optionswerte auch aus einem externen Frontend auslesen. Die Optionen müssen weiterhin **im Template definiert** werden (siehe [Optionen](/frontend/referenz/optionen)). Die Storefront-API liest die Werte nur aus und ersetzt die Definition nicht. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | ----------------------------------- | ------------- | --------------------- | ------------------- | ------------------- | ------------------- | | Wert einer Template-Option abfragen | `options/get` | | | | | ## Methoden für Optionen Mit dieser Methode wird der Wert einer einzelnen Template-Option bereitgestellt - sowohl für globale Optionen als auch für Optionen, die mit `attachTo` an einen Konfigurationsknoten gebunden sind. ### GET options/get Liefert den Wert einer Template-Option, analog zu [`$wsOptions.get(name, nodeId)`](/frontend/referenz/module/ws-options-template-optionen). Der Parameter `nodeId` ist optional und wird für Optionen angegeben, die an einen Konfigurationsknoten gebunden sind. **Beispiel-Aufruf**, der den Wert einer an eine Zahlungsart gebundenen Option ausliest: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/options/get?name=showPaymentIconInFooter&nodeId=payment.payment.bill ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------ | | `name` | string | Pflicht. Name der Option, wie im Template definiert. | | `nodeId` | string | Optional. ID des Konfigurationsknotens bei `attachTo`-Optionen. Ohne Angabe wird der globale Wert geliefert. | Es sind ausschließlich die Parameter `name` und `nodeId` erlaubt. Jeder weitere Query-Parameter führt zu `400 Bad Request` mit `error: "invalidParameters"` und einem Eintrag in `paramErrors`. #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "showPaymentIconInFooter", "nodeId": "payment.payment.bill", "value": true } ``` Wurde im Request kein `nodeId` übergeben, entfällt das Feld `nodeId` in der Antwort. Der Typ von `value` entspricht dem Typ der Option (z. B. `bool`, `string`, `int`). #### Statuscodes Der Endpunkt antwortet bei gültigen Parametern immer mit `200 OK`. Existiert keine Option mit dem angefragten `name`, enthält die Antwort das Feld `value` ohne Wert (`null`). Prüfen Sie deshalb im Frontend auf `value`, nicht auf den HTTP-Status. `404 Not Found` liefert der Endpunkt nur, wenn eine andere Methode als `GET` verwendet wird. *** ## Weiterführende Links * [Optionen](/frontend/referenz/optionen) – Template-Optionen definieren. * [\$wsOptions](/frontend/referenz/module/ws-options-template-optionen) – dieselben Werte im Template auslesen. # Storefront API Session-Handling Source: https://dokumentation.websale.de/schnittstellen/storefront-api/storefront-api-session-handling Sessions in der WEBSALE Storefront über die Storefront API erstellen und verwalten, damit Warenkorb und Merkliste über Requests hinweg konsistent bleiben. Das Storefront API Session-Handling stellt Funktionen bereit, um Sessions in der Storefront zu erstellen und zu verwalten. Damit lassen sich Benutzerzustände (z. B. anonymer Besuch oder eingeloggter Kunde) sowie sessiongebundene Daten wie Warenkorb und Merkliste konsistent über mehrere Requests hinweg nutzen. Die Session ist ein Bestandteil des Shops und zwingend erforderlich. Weiteren Informationen dazu finden Sie [hier](/konfiguration/general-allgemeine-shopeinstellungen). *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl** | **Endpunkte** | **GET** | **POST** | **PUT** | **DELETE** | | --------------------------------------- | ------------------------- | ------------------- | --------------------- | ------------------- | ------------------- | | Session erstellen | `session/create` | | | | | | Link zu einer Template-Seite erstellen. | `session/prepareRedirect` | | | | | ## Methoden für das Session-Handling Diese Methoden kümmern sich um das Session-Handling zwischen API und Storefront: Zunächst werden neue Session-IDs als technische Grundlage für alle weiteren API-Aufrufe erzeugt. Bei Bedarf werden vollständige Weiterleitungslinks zu Template-Seiten (z. B. Checkout) inklusive Übergabe der aktuellen Session aufgebaut. Über optionale Parameter lassen sich Zielseiten gezielt steuern (z. B. ein bestimmter Checkout-Schritt oder Hervorhebungen), während die eigentliche Session-ID sicher im Link eingebettet wird. ### POST session/create Folgender Aufruf erstellt eine Session-ID.
    Mehr Infos dazu: [Storefront API Basics](/schnittstellen/storefront-api/storefront-api-basics) ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/session/create ``` #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "id" : "bc37dffbf7a3d067a1b0a3040143c5a8d1a1d8651f79159f59d81705c9733c49" } ``` ### POST session/prepareRedirect Folgender Aufruf erzeugt einen vollständigen Link zu einer Template-Seite (z. B. `checkout.htm`) und übernimmt die aktuelle Session in die Storefront. Die Verwendung dieser Methode ist sinnvoll, wenn Ihr Shop gemischt aufgebaut ist, d. h., wenn einige Teile mit dem [WEBSALE-Template Theme](/frontend/die-basics/template-theme) und andere Teile mit der Storefront-API erstellt wurden. Der Endpunkt stellt sicher, dass beide Teile dieselbe Session verwenden. **Beispiel-Request, der einen vollständigen Link zur Template-Seite** `checkout` **erstellt und dabei die aktuelle Session mitnimmt** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "viewIdentifier": "checkout" } ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ---------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | string | **Pflichtfeld**
    ID der aktuellen Session. Mehr Informationen dazu: [Storefront API Basics](/schnittstellen/storefront-api/storefront-api-basics) | | `viewIdentifier` | string | **Pflichtfeld**
    Die ID, die in `storefrontApi.redirects` konfiguriert wird. Mehr dazu: [storefrontApi - Storefront-API](/konfiguration/storefrontapi-storefront-api) | | `parameters` | object | Optionale Werte, die der Zielseite in der Session bereitgestellt werden und dort über `$wsViews.storefrontApiLinkParameters` zur Verfügung stehen. Diese Werte erscheinen **nicht** in der URL. Geeignet z. B. für eine Rücksprung-Adresse in Ihre Storefront. | **Beispiel mit** `parameters` ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "viewIdentifier": "checkout", "parameters": { "leaveCheckoutHome": "https://ihre-storefront.de/" } } ``` Die Zielseite liest den Wert im Template aus: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Zurück zum Shop ``` **Werte in der Ziel-URL steuern Sie nicht hier, sondern in der Konfiguration.** Es gibt zwei gleichnamige `parameters`: * `parameters` im Konfigurationsknoten `storefrontApi.redirects` wird an die **Ziel-URL als Query-Parameter** angehängt und ist im Template wie jeder andere URL-Parameter verfügbar, z. B. über `$wsViews.current.paramList`. * `parameters` im **Request-Body** dieses Endpunkts wird in der **Session** hinterlegt und erscheint nicht in der URL. Faustregel: Soll der Wert in der Adresse stehen oder die angezeigte Seite bzw. den Schritt bestimmen, gehört er in die [Konfiguration](/konfiguration/storefrontapi-storefront-api). Soll er nur dem Template bekannt sein, gehört er in den Request-Body. #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "storeFrontLink": "https://demo.shop.websale.biz/checkout?sessionKey=U2swGmPcfOeSsVPLF4wCXw2wmYDDcuzh" } ``` (vollständige URL zur Ziel-Template-Seite inkl. Session-Übergabe) #### Gültigkeit und Aufruf des Links Der zurückgegebene Link ist **30 Sekunden** gültig. Danach lässt sich die Session darüber nicht mehr übernehmen: Der Shop legt in diesem Fall eine neue, leere Session an — ohne Fehlermeldung. Der Kunde sieht dann beispielsweise einen leeren Warenkorb im Bestellablauf. Rufen Sie `session/prepareRedirect` deshalb erst unmittelbar vor der Weiterleitung auf, also z. B. im Klick-Handler der Schaltfläche „Zur Kasse", nicht auf Vorrat beim Aufbau der Seite. Öffnen Sie den Link per echter Browser-Navigation, also über `window.location.href`, einen normalen Link oder eine serverseitige Weiterleitung. Ein Aufruf per `fetch` bzw. `XMLHttpRequest` genügt nicht: Der Kunde muss auf der Zielseite landen, damit der Shop dort die Session übernehmen kann. #### Fehlercodes | **Code** | **Beschreibung** | | ------------------------------ | ------------------------------------------------------------------------------------------------------------ | | `invalidParameters` | Der Request enthält ein unbekanntes Feld. Erlaubt sind ausschließlich `viewIdentifier` und `parameters`. | | `viewIdentifierNotSpecified` | `viewIdentifier` fehlt oder ist ein leerer String. Fehlertext: „View identifier not specified for redirect". | | `redirectNotFound` | Kein Konfigurationseintrag zum angegebenen `viewIdentifier` gefunden. | | `redisServicePoolInaccessible` | Internes Problem. Bitte wende dich an den Websale-Support. | | `redisServiceNotFound` | Internes Problem. Bitte wende dich an den Websale-Support. | **Mehrstufige Zielseiten.** Ist die Ziel-Vorlage mehrstufig aufgebaut — etwa ein Bestellablauf mit den Schritten Adresse, Zahlung, Übersicht und Abschluss — wählt sie den anzuzeigenden Schritt in der Regel über einen URL-Parameter. Dieser Parameter muss in `storefrontApi.redirects` hinterlegt sein, damit der erzeugte Link ihn enthält. Fehlt er, ruft der Kunde die Seite ohne Schrittangabe auf und die Vorlage zeigt statt des Formulars ihren allgemeinen Hinweistext. Der Aufruf wird dabei regulär mit HTTP 200 beantwortet, es entsteht keine Fehlermeldung. Welchen Parameter Ihre Vorlage erwartet, klären Sie bitte mit Ihrem Template-Ansprechpartner. # Storefront API URL-Resolution Source: https://dokumentation.websale.de/schnittstellen/storefront-api/storefront-api-url-resolution Eingehende Adressen einem Seitentyp zuordnen, Weiterleitungen erkennen und die URL eines Produkts oder einer Kategorie ermitteln. Die URL-Resolution API übersetzt zwischen Adressen und Shop-Ressourcen, und zwar in beide Richtungen. `urls/identify` beantwortet die Frage, welche Seite unter einer aufgerufenen Adresse angezeigt werden soll, und ist damit der Einstiegspunkt für das Routing einer eigenen Storefront. `urls/product` und `urls/category` gehen den umgekehrten Weg und liefern zu einer bekannten ID die passende Adresse, beispielsweise um Links in Listen und Navigationen zu erzeugen. Ein typischer Ablauf ist: Die Storefront übergibt die aufgerufene Adresse an `urls/identify`, erhält Seitentyp und ID zurück und lädt die Inhalte anschließend über die [Katalog API](/schnittstellen/storefront-api/storefront-api-katalog). Welcher Subshop antwortet, ergibt sich aus der Domain, gegen die die Aufrufe gehen. Mehr dazu unter [Storefront API Basics](/schnittstellen/storefront-api/storefront-api-basics). Da SEO-URLs je Subshop gepflegt werden, liefert dieselbe Adresse in verschiedenen Subshops unterschiedliche Ergebnisse. Die Endpunkte dieser Seite benötigen **keinen** `x-session`-Header. Ein mitgesendeter Header stört nicht. *** ## Unterstützte Methoden Angabe aller unterstützten Methoden. | **Befehl** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | -------------------------------- | --------------- | --------------------- | ------------------- | ------------------- | ------------------- | | Adresse einem Seitentyp zuordnen | `urls/identify` | | | | | | URL eines Produkts ermitteln | `urls/product` | | | | | | URL einer Kategorie ermitteln | `urls/category` | | | | | Alle anderen HTTP-Methoden beantworten die Endpunkte mit `404 Not Found`. ## Methoden für die URL-Resolution ### GET urls/identify Folgender Aufruf ordnet eine eingehende Adresse einer Shop-Ressource zu. Die Antwort sagt, welcher Seitentyp zu rendern ist, welche Ressource dazu geladen werden muss und ob stattdessen weitergeleitet werden soll. Der Endpunkt ist für Storefronts gedacht, die das Routing selbst übernehmen. Die Storefront gibt die vom Besucher aufgerufene Adresse hinein und entscheidet anhand der Antwort, ob sie eine Produktseite, eine Kategorieseite, eine Weiterleitung oder eine 404-Seite ausliefert. **Beispiel-Aufruf** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/urls/identify?url=/herren/schuhe/sneaker ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `url` | string | **Pflichtfeld**
    Der aufgerufene Pfad, URL-kodiert. Die Startseite wird als `/` übergeben. Weitere Query-Parameter werden mit `invalidParameters` abgelehnt. | Der Abgleich erfolgt zeichengenau gegen die gespeicherten SEO-URLs. Ein abweichender abschließender Schrägstrich oder eine abweichende Groß- und Kleinschreibung führen deshalb zu `404 Not Found`. Ein Query-String, der im Wert von `url` mitgegeben wird, führt ebenfalls zu `404 Not Found`. Zusätzliche Query-Parameter am Endpunkt selbst werden dagegen mit `400 invalidParameters` abgelehnt. Übergeben Sie ausschließlich den Pfad, mit führendem Schrägstrich und ohne Query-String. #### Antwortfelder | **Feld** | **Typ** | **Beschreibung** | | ---------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `found` | bool | `true`, wenn die Adresse einer Ressource zugeordnet werden konnte. `false` bedeutet, dass die Adresse dem Shop bekannt ist, die Ressource aber nicht mehr existiert. In diesem Fall steht in `redirect` das Weiterleitungsziel. | | `type` | string | Seitentyp, siehe folgende Tabelle. | | `id` | string | **Optional**
    Kennung der Ressource, mit der anschließend die Seitendaten geladen werden. Bei `Startpage` entfällt das Feld. | | `redirect` | string | **Optional**
    **Pfad**, auf den weitergeleitet werden soll. Das Feld ist nur vorhanden, wenn eine Weiterleitung erfolgen soll. | #### Seitentypen | **Typ** | **Inhalt von** `id` | **Beschreibung** | | ----------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | `Product` | Produkt-ID | Produktseite. Die Daten werden über `catalog/product/load` geladen. | | `Category` | Kategorie-ID | Kategorieseite. Die Daten werden über `catalog/category/load` geladen. | | `View` | Template-Pfad | Template-Seite mit eigener SEO-URL, beispielsweise `content/gtc.htm`. Das ist keine Katalog-ID, die Seite wird nicht über die Katalog API geladen. | | `Startpage` | entfällt | Startseite des Shops. Wird nur bei `url=/` geliefert. | Der Wert von `type` ist die Kennung des zuständigen View-Controllers. Kommen im Shop weitere Seitentypen mit eigenen SEO-URLs zum Einsatz, können auch deren Kennungen erscheinen. Fangen Sie unbekannte Werte deshalb ab und geben Sie in diesem Fall Ihre eigene 404-Seite aus. #### Antworten im Überblick | **Situation** | **HTTP** | `found` | `redirect` | **Empfohlene Reaktion** | | --------------------------------------------------------------------------- | -------- | -------- | ------------------ | --------------------------------------------- | | Adresse ist die aktuelle Adresse einer vorhandenen Ressource | 200 | `true` | entfällt | Seite regulär aufbauen | | Adresse ist eine Alt-Adresse derselben Ressource | 200 | `true` | aktuelle Adresse | 301 auf `redirect` | | Ressource gelöscht, im Shop ist ein Weiterleitungsziel hinterlegt | 200 | `false` | Weiterleitungsziel | 301 auf `redirect` | | Ressource gelöscht oder deaktiviert, **kein** Weiterleitungsziel hinterlegt | 200 | `true` | entfällt | Laden schlägt fehl, eigene 404-Seite ausgeben | | Adresse ist dem Shop unbekannt | 404 | entfällt | entfällt | eigene 404-Seite ausgeben | #### Beispiel-Response: vorhandene Ressource ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "found": true, "type": "Product", "id": "146-78608" } ``` #### Beispiel-Response: Startseite ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "found": true, "type": "Startpage" } ``` #### Beispiel-Response: Template-Seite ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "found": true, "id": "content/gtc.htm", "type": "View" } ``` #### Beispiel-Response: Alt-Adresse derselben Ressource ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "found": true, "type": "Product", "id": "146-78608", "redirect": "/herren/schuhe/sneaker-air-146-78608" } ``` Der Shop führt zu einer Ressource mehrere SEO-URLs. Ändert sich der generierte Pfad, beispielsweise durch eine Umbenennung, einen Kategoriewechsel oder eine manuell gesetzte URL, wird die neue Adresse zur aktuellen Adresse. Die bisherige bleibt als Alt-Adresse bestehen und wird nicht gelöscht, damit Lesezeichen und Suchmaschinen-Treffer weiter funktionieren. Damit beide Adressen nicht dauerhaft denselben Inhalt ausliefern, sollte die Storefront hier auf die aktuelle Adresse weiterleiten. Die Ressource selbst ist unverändert vorhanden, `type` und `id` beschreiben sie korrekt. #### Beispiel-Response: gelöschte Ressource mit Weiterleitungsziel ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "found": false, "type": "Product", "id": "146-78608", "redirect": "/herren/schuhe" } ``` In diesem Fall beschreiben `type` und `id` die **nicht mehr vorhandene** Ressource. Sie dürfen nicht zum Laden von Seitendaten verwendet werden, auswertbar ist hier nur `redirect`. #### Beispiel-Response: unbekannte Adresse ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} HTTP/1.1 404 Not Found ``` Der Response-Body ist leer. #### Auswertung in der Storefront Werten Sie die Antwort in dieser Reihenfolge aus: 1. **HTTP-Status 404**: Die Adresse ist dem Shop unbekannt. Geben Sie Ihre eigene 404-Seite aus. 2. **Feld** `redirect` **vorhanden**: Leiten Sie auf diesen Wert weiter, empfohlen mit Status 301. Das gilt sowohl für Alt-Adressen als auch für gelöschte Ressourcen. Prüfen Sie `redirect` deshalb **vor** `found`. 3. **Kein** `redirect`**,** `found` **ist** `true`: Bauen Sie die Seite regulär auf. `type` bestimmt den Seitentyp, `id` ist die Ressource für den anschließenden Aufruf von `catalog/product/load` beziehungsweise `catalog/category/load`. 4. **Der Ladeaufruf kommt leer zurück**: Die Ressource ist deaktiviert oder gelöscht, ohne dass ein Weiterleitungsziel hinterlegt ist. Geben Sie Ihre eigene 404-Seite aus. Ruft ein Besucher eine Alt-Adresse einer inzwischen gelöschten Ressource auf, greift zuerst die Weiterleitung auf die aktuelle Adresse. Erst der Folgeaufruf liefert `found: false` mit dem hinterlegten Weiterleitungsziel. In diesem Fall entstehen also zwei Weiterleitungen nacheinander. `found: true` bedeutet, dass die Adresse auflösbar ist, **nicht** dass die Ressource auslieferbar ist. Ein deaktiviertes Produkt ohne hinterlegtes Weiterleitungsziel liefert `found: true`. Diesen Fall muss die Storefront selbst erkennen, indem sie das Ergebnis des anschließenden Ladeaufrufs prüft. #### Aufbau des Feldes `redirect` `redirect` ist immer ein **Pfad** und beginnt mit `/`, es ist keine absolute URL. Der Wert kann direkt als `Location`-Header gesetzt werden. Zwei Formen sind möglich: * eine SEO-URL des Ziels, beispielsweise `/herren/schuhe` * eine technische Shop-URL, wenn zum Ziel keine SEO-URL existiert, beispielsweise `/?wsvc=Category&id=135-98530` Beide Formen werden vom Shop aufgelöst und können unverändert verwendet werden. #### Voraussetzung für Weiterleitungen gelöschter Ressourcen Ein Weiterleitungsziel für eine gelöschte Ressource wird nur ausgegeben, wenn im Shop `redirectToParentCategory` aktiv ist. Standard ist aktiv, siehe [urls.redirects](/konfiguration/urls-url-webadressen#urlsredirects-weiterleitungen-f%C3%BCr-fehlerhafte-urls). Ist die Option deaktiviert, verhält sich eine gelöschte Ressource wie eine Ressource ohne hinterlegtes Ziel. #### Fehlercodes | **Code** | **HTTP** | **Beschreibung** | | ------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `invalidParameters` | 400 | `url` fehlt, ist kein String, oder es wurden weitere Query-Parameter mitgegeben. Der Body enthält die Liste der beanstandeten Parameter. | *** ### GET urls/product Folgender Aufruf liefert die Adresse eines Produkts. Verwenden Sie ihn, um in Listen, Suchergebnissen oder Empfehlungen Links auf Produktseiten zu erzeugen, ohne das URL-Schema des Shops in der Storefront nachbauen zu müssen. **Beispiel-Aufruf** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/urls/product?productId=146-78608 ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------- | | `productId` | string | **Pflichtfeld**
    ID des Produkts. Weitere Query-Parameter werden mit `invalidParameters` abgelehnt. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "url": "/herren/schuhe/sneaker-air-146-78608" } ``` Zurückgegeben wird die aktuelle SEO-URL des Produkts als Pfad. Existiert für das Produkt keine SEO-URL, ist es die technische Shop-URL. #### Statuscodes Kann das Produkt nicht geladen werden, antwortet der Endpunkt mit `404 Not Found` und leerem Body. Fehlt `productId` oder wurden weitere Query-Parameter mitgegeben, antwortet der Endpunkt mit `400 Bad Request` und dem Fehlercode `invalidParameters`. *** ### GET urls/category Folgender Aufruf liefert die Adresse einer Kategorie, beispielsweise für den Aufbau der Navigation oder von Breadcrumbs. **Beispiel-Aufruf** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/urls/category?categoryId=135-98530 ``` #### Parameterübersicht | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | -------------------------------------------------------------------------------------------------------- | | `categoryId` | string | **Pflichtfeld**
    ID der Kategorie. Weitere Query-Parameter werden mit `invalidParameters` abgelehnt. | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "url": "/herren/schuhe" } ``` Zurückgegeben wird die aktuelle SEO-URL der Kategorie als Pfad. Existiert keine SEO-URL, ist es die technische Shop-URL. #### Statuscodes Kann die Kategorie nicht geladen werden, antwortet der Endpunkt mit `404 Not Found` und leerem Body. Fehlt `categoryId` oder wurden weitere Query-Parameter mitgegeben, antwortet der Endpunkt mit `400 Bad Request` und dem Fehlercode `invalidParameters`. *** ## Weiterführende Links * [Storefront API Basics](/schnittstellen/storefront-api/storefront-api-basics) - Basis-URL, Subshop-Auswahl über die Domain, Session-Handling und Fehlerformat. * [Storefront API Katalog](/schnittstellen/storefront-api/storefront-api-katalog) - Produkt- und Kategoriedaten zur ermittelten ID laden. * [urls - URL (Webadressen)](/konfiguration/urls-url-webadressen) - Aufbau der SEO-URLs und Verhalten bei nicht mehr gültigen Adressen. * [Storefront API Session-Handling](/schnittstellen/storefront-api/storefront-api-session-handling) - Übergabe der Session an eine Template-Seite. # Storefront API Warenkorb Source: https://dokumentation.websale.de/schnittstellen/storefront-api/storefront-api-warenkorb Warenkorb der Storefront über die Storefront API steuern: Artikel hinzufügen, Mengen ändern, Positionen entfernen, Werbemittelkennzeichen, Gutscheine und Summen pflegen. Die Warenkorb API steuert sämtliche Interaktionen rund um den Warenkorb: Artikel können hinzugefügt, Mengen geändert und Positionen entfernt werden. Zusätzlich stellt die API die Warenkorbinhalte inklusive Summen, Rabatten und Regeln wie Mindestbestellwerten oder Maximalbestellmengen bereit. Gutscheincodes lassen sich im Warenkorb erfassen, aktualisieren oder entfernen. Die Auswirkungen auf Rabatte und Summen werden entsprechend zurückgegeben. Versandkosten sind nicht Teil der Warenkorb-Antwort. `total`, `totalNet`, `totalGross` und `totalTax` sind reine Warenwert-Zwischensummen ohne Versand-, Zahlarten- und Zuschlagskosten sowie ohne Gutscheinabzug. Versandkosten (`shippingCost`), Zahlartenkosten (`paymentCost`), Zuschläge (`surchargeCost`), den Gutscheinabzug (`totalVoucher`) und die Endsumme liefern die Checkout-Endpunkte im Objekt `sum`. Die Schnittstelle liefert konsistente JSON-Antworten und informiert bei fehlerhaften Aktionen über eindeutige Fehlercodes (z. B. fehlende oder ungültige Produkt-/Positions-IDs, Mengenbeschränkungen, gesperrte Änderungen) inklusive Detailangaben, die eine schnelle Ursachenanalyse ermöglichen. Für die korrekte Verwaltung des Warenkorbs muss eine Session per `x-session` übermittelt werden. Mehr dazu [hier](/schnittstellen/storefront-api/storefront-api-basics). *** ## Unterstützte Methoden Angabe aller Unterstützten Methoden. | **Befehl** | **Endpunkte** | **GET** | **PUT** | **POST** | **DELETE** | | ------------------------------------------ | --------------------- | --------------------- | --------------------- | --------------------- | --------------------- | | Warenkorb lesen | `basket/item/get` | | | | | | Produkt(e) hinzufügen | `basket/items/add` | | | | | | Warenkorbposition ändern | `basket/items/update` | | | | | | Warenkorbposition entfernen | `basket/item/delete` | | | | | | Werbemittelkennzeichen-Konfiguration lesen | `config/inserts` | | | | | ## Fehlerformat Alle Fehler werden mit **HTTP 400** und folgendem Rumpf beantwortet: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "error": "actionFailed", "detail": "Action Failed", "actionErrors": [ { "code": "invalidProductId", "subCode": "", "field": "productId", "text": "…", "details": {} } ] } ``` * `error` = `invalidParameters` bei Fehlern in Parametern/Feldtypen (Details in `paramErrors`, Schlüssel = Parametername, Wert `{"type": "missing" | "invalidFormat" | "invalidValue" | "unknownField" | …}`). * `error` = `actionFailed` bei fachlichen Fehlern. Die in den folgenden Tabellen genannten Fehlercodes stehen dann in `actionErrors[].code`. * Ein Aufruf mit falscher HTTP-Methode wird mit **HTTP 404** beantwortet (nicht 405). * Fehlt die Session (`x-session`), wird mit **HTTP 400** geantwortet. ## Methoden für den Warenkorb Diese Methoden steuern den Warenkorb im Shop. Sie können den aktuellen Warenkorb auslesen, Produkte in der gewünschten Menge hinzufügen, bestehende Positionen ändern oder wieder entfernen. ### GET basket/item/get Der folgende Aufruf liefert den aktuellen Warenkorb mit allen Positionen und Summen (Netto/Brutto/Steuer). Die Daten unter „`items[].product`” repräsentieren den Zustand des Produkts zum Zeitpunkt, als es in den Warenkorb gelegt wurde. Ändert sich beispielsweise der Preis während des Bezahlvorgangs, wird die Bestellung trotzdem zum ursprünglichen, im Warenkorb gespeicherten Preis abgeschlossen. So werden Fehler oder Nachberechnungen verhindert. Welche Produktdaten in „`items[].product`” enthalten sind, wird in der Konfiguration der benutzerdefinierten Produktfelder festgelegt. Mehr dazu hier: [content - Katalog (Kategorien & Produkte)](https://websaleag-44ee7ea6.mintlify.app/konfiguration/content-katalog-kategorien-produkte#6-content-customproductfield-benutzerdefinierte-produktfelder).
    Dieser Befehl kann zum Anzeigen des Warenkorbs verwendet werden. **Beispiel-Aufruf für das Anzeigen des aktuellen Warenkorbs** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/basket/item/get ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | string | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](/schnittstellen/storefront-api/storefront-api-basics) | #### Beispiel Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "items": [ { "id": "0921e5b44dcd6034248f", "quantity": 1, "price": 59.99, "total": 59.99, "totalNet": 50.41, "totalTax": 9.58, "product": { "id": "155-03082", "name": "Wollmantel mit Bindegürtel", "price": 59.99 } }, { "id": "0d1b062c8225f817aa3e", "quantity": 3, "price": 499.99, "total": 1499.97, "totalNet": 1260.48, "totalTax": 239.49, "product": { "id": "179-33468", "name": "Handtasche", "price": 499.99 } } ], "lastBasketAction": "add", "lastUpdatedItem": { "id": "179-33468", "price": 499.99, "quantity": 3, "taxId": "19" }, "totalQuantity": 4, "total": 1559.96, "totalGross": 1559.96, "totalNet": 1310.89, "totalTax": 249.07, "totalTaxDeduction": 19.99, "isTaxExempt": true, "billingCountry": "DE", "shippingCountry": "DE", "usedExemptionRule": "shippingOnly" } ``` `billingCountry` und `shippingCountry` sind jeweils ein einzelner Länder-Code als String. Welches Format geliefert wird (`isoAlpha2` = `DE`, `isoAlpha3` = `DEU` oder `isoNum` = `276`), hängt von der Shop-Konfiguration ab. `lastBasketAction` kennzeichnet die zuletzt ausgeführte Änderung. Mögliche Werte: `add`, `delete`, `unknown`. Eine Mengenänderung setzt je nach Ergebnis `add` oder `delete`. Den Wert `update` gibt es nicht. `lastUpdatedItem` beschreibt die zuletzt geänderte Position. Achtung: `lastUpdatedItem.id` enthält die **Produkt-ID**, nicht die Warenkorbpositions-ID aus `items[].id`. Weitere Felder: `productNumber`, `categories` (string\[]), `parentCategories` (string\[]), `freeFields`, `voucherIds`. ### POST basket/items/add Mit diesem Aufruf wird ein Produkt in der gewünschten Menge in den Warenkorb gelegt. Durch mehrmaliges Ausführen des Befehls können mehrere Produkte hinzugefügt werden. Der Befehl kann verwendet werden, um ein Produkt zum Warenkorb hinzuzufügen. Falls mehrere Produkte hinzugefügt werden sollen, muss der Befehl entsprechend oft ausgeführt werden. **Beispiel-Aufruf für das Hinzufügen von drei Einheiten des Produktes mit der ID** `71-3953`**und der Geschenknachricht “Alles Gute!” zum Warenkorb** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} POST https://.de/api/v1/basket/items/add ``` Wird dasselbe Produkt (gleiche Variante und gleiche `freeFields`) mehrfach hinzugefügt, entsteht keine zweite Warenkorbposition: Die Menge der bestehenden Position wird um `quantity` erhöht und ihre `items[].id` bleibt unverändert. Set-Produkte werden nie zusammengeführt. #### Beispiel Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "productId": "71-3953", "quantity": 3, "insert": "09", "freeFields": { "giftMessage": "Alles Gute!" } } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld**
    ID der aktuellen Session.
    Mehr Informationen dazu: [Storefront API Basics](/schnittstellen/storefront-api/storefront-api-basics) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | ------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `productId` | string | **Pflichtfeld**
    ID des Produkts, das in den Warenkorb gelegt werden soll. | | `quantity` | int | **Pflichtfeld**
    Gibt an, wie oft das Produkt in den Warenkorb gelegt werden soll. | | `insert` | string | Optionales [Werbemittelkennzeichen](/frontend/funktionsubersicht/werbemittelkennzeichnung). Ist die Funktion aktiv, wird der Code serverseitig gegen die für das Produkt gültigen Codes geprüft: Bei einem gültigen Code wird er übernommen, andernfalls greift der konfigurierte Standardcode. **Ein übergebener Code wird zusätzlich als sessionweiter Code gespeichert und gilt als Vorgabe für alle danach hinzugefügten Positionen. Wird `insert` weggelassen, greift der zuletzt gesetzte sessionweite Code.** Ist die Funktion inaktiv, wird der Wert ignoriert. | | `freeFields` | Objekt (String → String) | Freie Schlüssel/Wert-Paare, die an der Position angehängt und in die Bestelldaten exportiert werden können. | Es sind ausschließlich die oben genannten Felder erlaubt. Jedes weitere Feld im Request-Body führt zu HTTP 400 mit `error: "invalidParameters"` und einem Eintrag `unknownField` in `paramErrors`. **Hinweis zu Set-Produkten:** Der Endpunkt akzeptiert ausschließlich die vier oben genannten Felder. Jedes weitere Feld wird mit `unknownField` abgelehnt. Die Variantenauswahl für Set-Unterartikel (`setChildVar_`) kann daher derzeit nicht übergeben werden. Set-Produkte, deren Unterartikel Varianten haben, sind über die Storefront-API nicht bestellbar. #### Beispiel Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "basket": { "items": [ { "id": "f28e67292c99759e5fb9", "quantity": 3, "price": 139, "insert": "09", "itemNumberWithInsert": "71-3953-09", "total": 417, "totalNet": 350.42, "totalTax": 66.58, "freeFields": { "giftMessage": "Alles Gute!" }, "product": { "id": "71-3953", "name": "Beispielprodukt", "price": 139, "taxRateId": "1", "custom": { "...": "benutzerdefinierte Produktfelder laut Konfiguration" } } } ], "totalQuantity": 3, "total": 417, "totalGross": 417, "totalNet": 350.42, "totalTax": 66.58 } } ``` Jede Position in `items[]` kann außerdem folgende Felder enthalten: | Feld | Typ | Beschreibung | | ------------------------------------------------ | ------------------------ | ---------------------------------------------------------------------- | | `id` | string | ID der Warenkorbposition (für `update`/`delete`). | | `quantity` | float | Menge der Position. | | `price` | float | Einzelpreis der Position. | | `orgPrice` | float | Ursprünglicher Einzelpreis vor Rabatt. | | `discountPrice` | float | Rabattbetrag der Position. | | `total` / `totalGross` / `totalNet` / `totalTax` | float | Positionssumme brutto/netto/Steueranteil. | | `oneTimeFee` | float | Einmalgebühr der Position. | | `insert` | string | Aufgelöstes Werbemittelkennzeichen der Position. | | `itemNumberWithInsert` | string | Produktnummer inklusive Werbemittelkennzeichen. | | `freeFields` | Objekt (String → String) | Freie Felder der Position. | | `voucherIds` | string\[] | IDs der zu dieser Position generierten Gutscheine (Gutscheinprodukte). | | `isSetProduct` | bool | Nur bei Set-Oberartikeln vorhanden und dann `true`. | | `isSetChild` | bool | Nur bei Set-Unterartikeln vorhanden und dann `true`. | | `parentBasketItemId` | string | Nur bei Set-Unterartikeln: ID des Set-Oberartikels. | | `product` | Objekt | Produktdaten zum Zeitpunkt der Warenkorbaufnahme. | Nicht sichtbare Positionen (`isVisible = false`) und ausgeblendete Set-Unterartikel erscheinen nicht in `items`. #### Fehlercodes | **Fehlercode** | **Beschreibung** | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | `invalidProductId` | Das angefragte Produkt existiert nicht. | | `invalidVariantId` | Die angefragte Variante existiert nicht. | | `insufficientAmount` | Es sind nicht genügend Produkte auf Lager. | | `quantityExceeded` | Die maximal erlaubte Anzahl für dieses Produkt wurde überschritten (zusätzliche Details unter “details” - siehe unten). | | `childProductOnly` | Das Produkt kann nur als Bestandteil eines Sets bestellt werden. | | `expressCheckoutNotAllowed` | PayPal Express Checkout ist aktiv - der Warenkorb darf aktuell nicht verändert werden. | | `noVariantFound` | Für ein Variantenprodukt wurde keine Variante angegeben (Produkt-ID enthält keine Variantenauswahl). | Bei `quantityExceeded` enthält `details` die Felder `productId` (betroffene Produkt-ID), `quantity` (angeforderte Gesamtmenge) und `maxQuantity` (global konfigurierte Höchstmenge pro Position). `subCode` enthält die Produkt-ID, `field` den Wert `quantity`. Zusätzlich zur globalen Höchstmenge kann ein Produkt über das Produktfeld für die Maximalmenge eine niedrigere Grenze haben. ### PUT basket/items/update Mit folgendem Aufruf kann man eine bestehende Warenkorb-Position aktualisieren bzw. ändern, typischerweise die Menge. Er ist für Mengenänderungen im Warenkorb verwendbar. **Beispiel-Aufruf für das ändern der Warenkorbposition mit der ID** `0921e5b44dcd6034248f`**auf die Menge 2** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} PUT https://.de/api/v1/basket/items/update ``` #### Beispiel-Request (Menge einer Position auf 2 reduzieren) ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "basketItemId": "0921e5b44dcd6034248f", "quantity": 2 } ``` Hinweis: Wenn `quantity` auf 0 gesetzt wird, wird die Position aus dem Warenkorb entfernt. Alternativ kann die Position auch über `DELETE basket/delete` gelöscht werden. #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld** ID der aktuellen Session. Mehr Informationen dazu: [Storefront API Basics](../storefront-api/storefront-api-basics.md#2-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | -------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `basketItemId` | string | **Pflichtfeld** ID der Warenkorb-Position (entspricht `items[].id` aus dem Warenkorb. | | `quantity` | int | **Pflichtfeld** Neue Menge der Position. | | `productId` | string | Ändert in einer bestehenden Warenkorb-Position das zugehörige Produkt (z.B. wechsel der Größe / Farbe / Variante). Beispiel: T-Shirt M → T-Shirt L (gleiches Modell, andere Variante) | | `insert` | string | Setzt oder ändert das [Werbemittelkennzeichen](/frontend/funktionsubersicht/werbemittelkennzeichnung) der Position. Verhält sich wie beim Hinzufügen: Ein gültiger Code wird übernommen, sonst greift der Standardcode. Ein übergebener Code wird außerdem als sessionweiter Code für nachfolgende Positionen gespeichert. Bei inaktiver Funktion wird der Wert ignoriert. | | `freeFields` | Object (String → String) | Neue freie Schlüssel/Werte-Paare für die Position (werden in Bestelldaten exportiert). Beispiel: Personalisierung des Produkts. `"freeFields": { "engraving": "A.K.", "giftMessage": "Alles Gute!", "costCenter": "MKT-2025-11", "configId": "cfg_7f2a9" }` | Es sind ausschließlich die oben genannten Felder erlaubt. Jedes weitere Feld im Request-Body führt zu HTTP 400 mit `error: "invalidParameters"` und einem Eintrag `unknownField` in `paramErrors`. #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "basket": { "items": [ { "id": "0921e5b44dcd6034248f", "quantity": 2.0, "price": 59.99, "total": 119.98, "totalGross": 119.98, "totalNet": 100.82, "totalTax": 19.16, "freeFields": {}, "product": { "id": "155-03082", "name": "Wollmantel mit Bindegürtel", "price": 59.99 }, "voucherIds": [] }, { "id": "0d1b062c8225f817aa3e", "quantity": 3.0, "price": 499.99, "total": 1499.97, "totalGross": 1499.97, "totalNet": 1260.48, "totalTax": 239.49, "freeFields": {}, "product": { "id": "179-33468", "name": "Handtasche", "price": 499.99 }, "voucherIds": [] } ], "totalQuantity": 5.0, "total": 1619.95, "totalGross": 1619.95, "totalNet": 1361.3, "totalTax": 258.65 } } ``` `lastBasketAction`, `lastUpdatedItem`, `totalCommission` und `totalWeight` liefert nur der Lese-Endpunkt `GET basket/items/get`. Die Felder der Positionen in `items[]` entsprechen denen bei `POST basket/items/add`, siehe dort. #### Fehlercodes | **Fehlercode** | **Beschreibung** | | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `invalidBasketItemId` | Die angegebene Positions-ID gehört nicht zum aktuellen Warenkorb. | | `insufficientAmount` | Nicht genügend Bestand, um die gewünschte Menge zu setzen. | | `quantityExceeded` | Die maximal erlaubte Anzahl für dieses Produkt wurde überschritten. Zusätzliche Details siehe unten. | | `itemNotChangeable` | Die Position darf nicht verändert werden (z.B. automatisch hinzugefügter Artikel) | | `invalidProductId` | Die Produkt-ID existiert nicht, oder ein Set verweist auf ein nicht existentes Set-Unterprodukt bzw. eine nicht existente Unterartikel-Variante. | | `expressCheckoutNotAllowed` | Ein Express-Checkout ist aktiv - der Warenkorb darf aktuell nicht verändert werden. | | `basketLocked` | Der Warenkorb ist gesperrt (beispielsweise durch einen Freigabeprozess bei Sub-Accounts) und darf nicht verändert werden. | | `missingBasketItemId` | `basketItemId` wurde nicht übergeben oder ist leer. | | `invalidQuantity` | Die Menge ist keine positive Ganzzahl (bzw. 0 bei erlaubtem Entfernen) oder die Position ist ein Set-Unterartikel, dessen Menge nicht direkt geändert werden darf. | | `internalError` | Ein Set-Produkt konnte beim Neuaufbau nicht gespeichert werden. | Bei `quantityExceeded` enthält `details` die Felder `productId` (betroffene Produkt-ID), `quantity` (angeforderte Gesamtmenge) und `maxQuantity` (global konfigurierte Höchstmenge pro Position). `subCode` enthält die Produkt-ID, `field` den Wert `quantity`. ### DELETE basket/item/delete Mit folgendem Aufruf kann eine bestehende Warenkorb-Position dauerhaft entfernt werden. Mit diesem Befehl können Artikel aus dem Warenkorb entfernt werden. **Beispiel-Aufruf für das Löschen des Produktes mit der Item-ID** `0d1b062c8225f817aa3e` ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} DELETE https://.de/api/v1/basket/item/delete ``` #### Beispiel-Request ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "basketItemId": "0d1b062c8225f817aa3e" } ``` #### Parameterübersicht #### Header-Parameter | **Parameter** | **Beschreibung** | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-session` | **Pflichtfeld** ID der aktuellen Session. Mehr Informationen dazu: [Storefront API Basics](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/storefront-api/storefront-api-basics#3-session-handling) | #### Body-Parameter | **Parameter** | **Typ** | **Beschreibung** | | -------------- | ------- | ----------------------------------------------------------------------------------- | | `basketItemId` | String | **Pflichtfeld** ID der Warenkorb-Position (entspricht `items[].id` im Warenkorb). | #### Beispiel-Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "basket": { "items": [], "lastBasketAction": "delete", "lastUpdatedItem": { "id": "0d1b062c8225f817aa3e", "price": 499.99, "quantity": 0.0, "taxId": "19", "voucherIds": [] }, "total": 0.0, "totalCommission": 0.0, "totalGross": 0.0, "totalNet": 0.0, "totalQuantity": 0.0, "totalTax": 0.0, "totalWeight": 0.0 } } ``` #### Fehlercodes | **Fehlercode** | **Beschreibung** | | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `invalidBasketItemId` | Die angegebene ID gehört nicht zum aktuellen Warenkorb. | | `invalidChildItemDelete` | Es wurde versucht, einen Set-Unterartikel einzeln zu entfernen. Unterartikel werden automatisch mit dem zugehörigen Set-Oberartikel entfernt und können nicht separat gelöscht werden. (`field` = `childItemDelete`) | | `itemNotRemovable` | Die Position darf nicht entfernt werden (z.B. automatisch hinzugefügter Artikel). | | `expressCheckoutNotAllowed` | PayPal Express ist aktiv - der Warenkorb darf derzeit nicht verändert werden. | | `basketLocked` | Der Warenkorb ist gesperrt (beispielsweise durch einen Freigabeprozess bei Sub-Accounts) und darf nicht verändert werden. | | `missingBasketItemId` | `basketItemId` wurde nicht übergeben oder ist leer. | ## Methoden für die Konfiguration ### GET config/inserts Der folgende Aufruf liefert die aktuelle Konfiguration der [Werbemittelkennzeichnung](/frontend/funktionsubersicht/werbemittelkennzeichnung). Nutzen Sie ihn, um in einer Storefront-Anwendung zu entscheiden, ob ein Eingabefeld für das Werbemittelkennzeichen angezeigt wird und wie die Anzeige aus Produktnummer und Code zusammengesetzt ist. **Beispiel-Aufruf** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} GET https://.de/api/v1/config/inserts ``` #### Parameterübersicht #### Header-Parameter Dieser Endpunkt benötigt keine Session. Der Header `x-session` ist optional und wird ignoriert. #### Beispiel Response ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "enabled": true, "defaultInsertCode": "", "separator": "-", "position": "after" } ``` | **Feld** | **Typ** | **Beschreibung** | | ------------------- | ------- | ------------------------------------------------------------------------------------------- | | `enabled` | bool | Ob die Werbemittelkennzeichnung im Shop aktiv ist. | | `defaultInsertCode` | string | Standardcode, der greift, wenn kein oder ein ungültiger Code erfasst wurde. Kann leer sein. | | `separator` | string | Trennzeichen zwischen Produktnummer und Code (beispielsweise `-`). | | `position` | string | Position des Codes relativ zur Produktnummer: `before` oder `after`. | # Übersicht - strapi CMS Source: https://dokumentation.websale.de/strapi-cms Strapi als Headless-CMS für WEBSALE: Anmeldung, Inhaltspflege, Komponenten, Sammlungen und Anbindung an das Template Theme der Storefront. Diese Dokumentation beschreibt die Bedienung von Strapi im WEBSALE-Kontext – vom Anmelden und Verwalten von Inhalten bis hin zu Anpassungen und, bei Bedarf, der Erweiterung um zusätzliche Komponenten. [Strapi](https://strapi.io/) ist ein modernes Content-Management-System (CMS) zur Verwaltung von Shop-Inhalten. Als Headless-CMS arbeitet es nach dem API-First-Prinzip: Inhalte werden in Strapi gepflegt und anschließend über die JSON-Schnittstelle an den Shop ausgeliefert. Dadurch eignet sich Strapi besonders für größere und komplexere Projekte. Strapi ist kein Baukastensystem (Page-Builder) wie Wix, Jimdo oder WordPress Elementor. Es dient der Inhaltspflege – die Gestaltung (Design/Layout) entsteht nicht in Strapi, sondern im [Template Theme](/frontend/die-basics/template-theme) der Storefront. Es gibt keine Design-Bibliotheken mit fertigen Elementen zum Auswählen per Drag & Drop und in Strapi sieht man das fertige Seiten-Design nicht vorab. Stattdessen arbeitet man mit Eingabemasken und Formularen: Beispielsweise werden ein Bild, eine Überschrift und ein Link in definierte Felder eingetragen. Wie diese Inhalte im Shop dargestellt werden (beispielsweise als Slideshow, Bildergalerie oder Teaser), wird einmalig im [Template Theme](/frontend/die-basics/template-theme) festgelegt. Das Prinzip ist vergleichbar mit Produkt- und Kategoriedaten aus PIM oder Warenwirtschaft: Informationen werden in Datenfeldern gepflegt, und das Shop-Template definiert die Ausgabe in Kategorie- und Produktseiten. Dieses Vorgehen entspricht dem WEBSALE-Ansatz für die [Storefront](/frontend): WEBSALE liefert keinen Drag-and-Drop-Page-Builder und keine starren Designvorlagen. Die Inhalte stammen aus verschiedenen Datenquellen (beispielsweise WaWi, PIM, CMS), während die Darstellung im [Template Theme](/frontend/die-basics/template-theme) über HTML-Templates sowie CSS- und JavaScript-Dateien individuell umgesetzt wird. Die Erstellung und Anpassung des [Template Themes](/frontend/die-basics/template-theme) erfolgt in der Regel durch Webdesigner und Frontend-Entwickler. Dabei werden auf Basis der WEBSALE Template Engine HTML-Templates aufgebaut, per CSS gestaltet und bei Bedarf mit JavaScript um Logik und Interaktionen ergänzt. Wie die Storefront grundsätzlich aufgebaut und angepasst werden kann, ist in der [Frontend-Dokumentation](/frontend) beschrieben. Für die redaktionelle Qualitätssicherung steht ein Test-Ansatz zur Verfügung: Inhalte können zunächst nur für den Test publiziert und im Shop über den [Shop-Testmodus](/frontend/referenz/module/wstestmode) angesehen (Vorschauansicht) und geprüft werden. Änderungen können somit iterativ vorgenommen werden, bis die Inhalte final sind. Erst danach werden die Inhalte im Live-Kontext publiziert und sind für Endkunden sichtbar. So lassen sich Inhalte auch vorbereiten und intern prüfen lassen; Freigaben erfolgen im Standard manuell (ohne automatisierte Freigabe-Workflows). Der [WEBSALE Demoshop](https://demo.shop.websale.biz/) wird standardmäßig mit dem CMS Strapi ausgeliefert und enthält bereits einen definierten Satz an Eingabemasken und passenden Darstellungen. *** ## SEO-Meta-Daten für CMS-Seiten Für CMS-Seiten steht im Standard ein Meta-Info-Plugin zur Verfügung. Darüber werden die SEO-relevanten Felder einer Seite, wie SEO-URL, Meta-Title, Meta-Description und Robots, zentral und unabhängig von der freien Content-Type-Modellierung gepflegt. So lassen sich diese Werte pro Seite setzen, ohne sie in jedem kundenspezifischen Content-Type einzeln modellieren zu müssen. Die so gepflegten Werte werden an den Shop übergeben und dort wie die Meta-Daten anderer Seiten verarbeitet. Der zugehörige Konfigurationsknoten ist [`seoMetaData`](/konfiguration/seometadata-meta-daten-seo-texte) – insbesondere `viewSchemes`, das die Meta-Daten für CMS-Seiten analog zu Kategorien, Produkten und der Startseite bereitstellt. Eine ausführliche Einordnung des Meta-Info-Plugins befindet sich unter [Grundlagen & Architektur von strapi](/strapi-cms/grundlagen-architektur-von-strapi#seo-meta-daten-fur-cms-seiten-meta-info-plugin). *** ## Welche Inhalte sind relevant ### Inhaltspflege und Änderungen an bestehenden Inhalten Wollen Sie nur Inhalte pflegen oder bestehende Inhalte anpassen, reicht es die folgenden beiden Kapitel zu lesen. * [Anmeldung & Benutzerverwaltung von Strapi](/strapi-cms/anmeldung-benutzerverwaltung-von-strapi) * [Inhalte anpassen von Strapi](/strapi-cms/inhalte-anpassen-in-strapi) Für das reine Pflegen von Inhalten sind keine Entwicklungskenntnisse erforderlich. ### Neue Inhaltselemente erstellen Wenn neue Inhaltselemente benötigt werden oder bestehende Eingabemasken und Strukturen erweitert werden sollen, sind zusätzlich diese Kapitel relevant: * [Grundlagen & Architektur von Strapi](/strapi-cms/grundlagen-architektur-von-strapi) * [Komponenten & Sammlungen in Strapi](/strapi-cms/komponenten-sammlungen-in-strapi) * [Templates für Strapi Inhalte anpassen](/strapi-cms/templates-fur-strapi-inhalte-anpassen) Für neue Komponenten/Formulare sowie Erweiterungen von Strukturen und Darstellungen sind Kenntnisse in HTML, CSS, JavaScript, JSON sowie der WEBSALE Template Engine erforderlich. *** ## Inhaltsübersicht * [Anmeldung & Benutzerverwaltung von strapi](/strapi-cms/anmeldung-benutzerverwaltung-von-strapi) — Auf dieser Seite wird beschrieben, wie der Zugang zum strapi CMS funktioniert und wie Benutzer in strapi verwaltet werden. Dazu gehören das initiale Login, grundlegende Einstellungen wie die Sprache sowie das Anlegen, Bearbeiten und Löschen von Benutzern. * [Grundlagen & Architektur von strapi](/strapi-cms/grundlagen-architektur-von-strapi) — Auf dieser Seite werden die grundlegenden Konzepte und die Architektur von strapi erklärt. Ziel ist es, ein Verständnis dafür zu schaffen, wie strapi als Headless-CMS aufgebaut ist, welche Rolle der API-First-Ansatz spielt und wie Inhalte aus Strapi in den WEBSALE Shop ausgeliefert werden. * [Komponenten & Sammlungen in strapi](/strapi-cms/komponenten-sammlungen-in-strapi) — Auf dieser Seite wird erklärt, wie Inhalte in Strapi strukturiert werden und welche Rolle Komponenten, Sammlungen und Einzel-Einträge dabei spielen. Sie erfahren, wofür die jeweiligen Content-Typen verwendet werden, wie sie sich unterscheiden und wie sie im Content-Manager zur Pflege von Inhalten zusammenspielen. * [Inhalte anpassen in strapi](/strapi-cms/inhalte-anpassen-in-strapi) — Auf dieser Seite wird beschrieben, wie Inhalte im Strapi CMS im WEBSALE-Kontext gepflegt und angepasst werden. Dazu gehören das Bearbeiten bestehender Inhalte, das Anlegen neuer Inhalte sowie die grundlegenden Unterschiede zwischen Speichern und Veröffentlichen – inklusive Hinweisen zum Vorab-Testen. * [Templates für strapi Inhalte anpassen](/strapi-cms/templates-fur-strapi-inhalte-anpassen) — Auf dieser Seite wird beschrieben, wie die Shop-Templates bei veränderten oder neuen strapi Komponenten oder Inhalte angepasst werden müssen. # Anmeldung & Benutzerverwaltung von strapi Source: https://dokumentation.websale.de/strapi-cms/anmeldung-benutzerverwaltung-von-strapi Zugang zum strapi CMS einrichten: CMS-URL, erster Login, Spracheinstellungen sowie Anlegen, Bearbeiten und Berechtigen von Benutzern und Rollen. Auf dieser Seite wird beschrieben, wie der Zugang zum strapi CMS funktioniert und wie Benutzer in strapi verwaltet werden. Dazu gehören das initiale Login, grundlegende Einstellungen wie die Sprache sowie das Anlegen, Bearbeiten und Löschen von Benutzern. Zusätzlich werden die Rechte- und Rollenverwaltung erläutert, damit Zugriffe gezielt gesteuert und Benutzer passend zu ihren Aufgaben berechtigt werden können. *** ## Anmeldung bei strapi CMS Um Inhalte des Online-Shops über das strapi CMS zu verwalten, muss man sich zunächst anmelden. Dies geschieht über eine spezielle URL, die direkt an das CMS des Shops angebunden ist. Die URL zum CMS wird in der Regel aus der ShopID und dem Zusatz "cms" gebildet. Diese URL wird ebenfalls bei der Shop-Bereitstellung von WEBSALE zur Verfügung gestellt. Zum Beispiel: Wenn die ShopID Ihres Shops `mustershop` lautet, wird die CMS-URL `mustershop-cms.websale.net` sein. Über das Admin-Interface des Shops gibt es auch einen direkten Einstieg zu strapi, diesen findet man im Menü unter “Templates und Content” → “CMS (Strapi)”: Strapi Anmeldung Nachdem die CMS-URL aufgerufen wurde, muss man sich mit Benutzername und Passwort anmelden (es handelt sich nicht um die Zugangsdaten, die für das Admin-Interface des Shops benötigt werden). Diese Zugangsdaten erhält man in der Regel bei der Ersteinrichtung des Kontos oder von Ihrem Administrator. Mit diesen Anmeldedaten kann dann auf die Verwaltungsoberfläche zugegriffen und begonnen werden, die Inhalte des Shops zu pflegen und zu aktualisieren. ### Initiales Login **Erhalt des Anmeldelinks:** Bei der Einrichtung des CMS-Systems durch WEBSALE wird eine E-Mail mit einem Link versendet, der direkt zur Anmeldeseite des CMS führt.\ Dieser Link ist für das initiale Einrichten des Zugangs gedacht. **Passwort setzen:** Beim ersten Besuch des Links wird man aufgefordert, ein Passwort für das Konto zu festzulegen. Dieses Passwort wird für zukünftige Anmeldungen benötigt. **Erster Login:** Sobald ein neues Passwort gesetzt wurde, ist die Anmeldung mit E-Mail-Adresse und dem neu festgelegten Passwort möglich. **Zugangsdaten ändern:** Ab dem Zeitpunkt des ersten erfolgreichen Logins besteht die Möglichkeit, die Zugangsdaten über das Kundenkonto in Strapi zu ändern oder zu aktualisieren. *** ## Startseite nach erfolgreichem Login Nach erfolgreichem Login gibt es unterschiedliche Einstiegsmöglichkeiten: Strapi Startseite Auf der Startseite werden verschiedene Einstiegsmöglichkeiten dargestellt, wie beispielsweise die Verlinkung zur eigenen Dokumentation von Strapi, die wir für das allgemeine Verständnis der Funktionsweise des CMS empfehlen. *** ## Sprache ändern Die Sprache der Strapi-Oberfläche ist standardmäßig auf Englisch voreingestellt und kann in den Einstellungen geändert werden. Aktuell werden Deutsch und Englisch angeboten. Folgende Schritte sind zur Änderung der Sprache notwendig: * **Zugang zum Profilbereich**: Der Zugang zum Profilbereich befindet sich im linken unteren Bereich des Menüs und öffnet sich durch einen Klick auf das Profilbild oder die Initialen. * **Navigation zum Profil-Menü**: In dem sich aufklappenden Menü muss die Option “Profil” gewählt werden. * **Spracheinstellung ändern**: Unter dem Abschnitt “Bedienung” befindet sich der Menüpunkt “Sprache der Oberfläche”, hier kann nun die gewünschte Sprache aus den verfügbaren Optionen ausgewählt werden. * **Änderungen speichern**: Um die neue Spracheinstellung zu übernehmen, muss die Konfiguration durch einen Klick auf “Speichern” im rechten oberen Bereich gespeichert werden. *** ## Benutzer verwalten Das Anlegen neuer Benutzerzugänge für das CMS ermöglicht es, anderen Teammitgliedern oder Mitarbeitern den Zugang zu Strapi zu gewähren. ### Initialer Benutzer Der erste angelegte Benutzer verfügt standardmäßig über Administrator-Rechte und ist somit befugt, neue Benutzer anzulegen. Zudem hat er Zugriff auf alle Inhalte und Konfigurationsmöglichkeiten, die WEBSALE in Strapi zur Verfügung stellt. ### Neue Benutzer erstellen * Navigieren Sie in der Menüleiste auf der linken Seite zu „Einstellungen“. * Klicken Sie unter „Administrationsoberfläche“ auf „Benutzer“. * Klicken Sie rechts oben auf den Button „Benutzer einladen“. Dies öffnet ein Formular, in dem die Details für den neuen Benutzer eingegeben werden können. * Geben Sie den Vor- und Nachnamen sowie die E-Mail-Adresse des neuen Nutzers an. Diese Informationen sind notwendig, um den Einladungslink zu erstellen und dem Nutzer die Registrierung zu ermöglichen. * Wählen Sie eine Rolle für den neuen Benutzer aus. Die zugewiesene Rolle bestimmt, welche Berechtigungen der Nutzer im System hat. Dies umfasst, was er sehen, bearbeiten oder nicht zugreifen kann. * Standardmäßig gibt es drei vordefinierte Rollen, aber es ist auch möglich, zusätzliche Rollen anzulegen. Kunden können entweder selbst neue Rollen definieren oder WEBSALE damit beauftragen (siehe Abschnitt zur Rechte- und Rollenverwaltung). * Nachdem alle Informationen eingegeben und die Rolle zugewiesen wurde, wird ein Einladungs-Link erzeugt. Dieser Link kann dann an den entsprechenden Nutzer gesendet werden, um ihn zum Abschluss seiner Registrierung einzuladen. ### Benutzer löschen * Gehen Sie erneut in die „Benutzer“-Sektion unter „Einstellungen“. * Wählen Sie den Benutzer aus, den Sie entfernen möchten. * Nutzen Sie die Option zum Löschen, die in der Benutzeroberfläche verfügbar ist, um den Benutzer dauerhaft aus dem System zu entfernen. *** ## Rechte und Rollenverwaltung Im Strapi-Admin-Panel kann die Zugriffskontrolle durch das Erstellen von Rollen und das Zuweisen von spezifischen Berechtigungen an diese Rollen effektiv verwaltet werden. Anschließend ist es möglich, diese Rollen den Benutzern des Systems zuzuordnen. ### Vordefinierte Rollen Im Standard liefert WEBSALE die folgenden 3 Standard-Rollen mit entsprechenden Berechtigungen aus: * **Autor (Author):** Autoren können bereits Inhalte bearbeiten und neue Inhalte erstellen. * **Bearbeiter (Editor):** Redakteure können Inhalte verwalten und veröffentlichen, auch die von anderen Nutzern. Sie können keine Inhalte selbst erstellen. * **Super Admin (Admin):** Super-Admins können auf alle Funktionen, Einstellungen und Inhalte zugreifen und diese verwalten. ### Rollen erstellen und verwalten * Gehen Sie im linken Menü zu „Einstellungen“ und wählen Sie dann „Rollen“ unter der Administrationsoberfläche aus. * Dort kann eine vorhanden Rolle bearbeitet oder durch Klicken auf „Rolle hinzufügen“ eine neue Rolle erstellt werden. * Geben Sie der Rolle einen aussagekräftigen Namen und fügen Sie eine Beschreibung hinzu, die den Zweck und die Verantwortlichkeiten der Rolle klar definiert. * Die Berechtigungen sind unterteilt in „Collections“, „SingleTypes“, „Plugins“ und „Settings“.\ Für mehr Informationen zu den verfügbaren Rechten verweisen wir auf die [Strapi Dokumentation](https://docs.strapi.io/user-docs/users-roles-permissions). * Für **Content-Typen** (Collections, SingleTypes) können gängige Berechtigungen wie Lesen, Schreiben, Löschen und Veröffentlichen eingestellt werden. * Bei **Plugins und Settings** sind die Berechtigungen etwas komplexer. Hier können beispielsweise Berechtigungen für das Erstellen von Internationalisierungen, das Hochladen von Bildern oder Medien, oder das Anlegen neuer Webhooks vergeben werden. Es empfiehlt sich, die spezifischen Optionen in der Strapi-Dokumentation nachzuschlagen, um eine detaillierte Übersicht zu erhalten. * Nachdem alle Einstellungen getroffen wurden, speichern Sie die Rolle, um die Änderungen zu übernehmen. ### Benutzern Rollen zuweisen * Gehen Sie wiederum über „Einstellungen“ zur „Benutzerverwaltung“. * Hier besteht die Möglichkeit, entweder einen bereits existierenden Nutzer auszuwählen oder einen neuen Nutzer anzulegen. Des Weiteren besteht die Möglichkeit, Benutzer per E-Mail mithilfe eines Einladungslinks einzuladen. * Im Nutzerprofil besteht im Bereich “Rollen” die Möglichkeit, dem Nutzer eine oder mehrere Rollen zuzuweisen. * Nach Auswahl der gewünschten Rollen müssen die Änderungen durch einen Klick auf “Speichern” im rechten oberen Bereich gespeichert werden. ### Hinweis zu Endbenutzer-Rollen * Der Bereich "Nutzer & Berechtigungen-Plugin" in Strapi wird vorrangig für die Verwaltung von Berechtigungen genutzt, die sich auf den WEBSALE-Strapi-Connector beziehen. * In diesem Kontext ist die Verwaltung von Endbenutzer-Rollen vor allem für die Kontrolle des Zugriffs auf die API relevant, über die JSON-Daten abgerufen werden. * Endbenutzer-Rollen, die in anderen Kontexten dazu dienen könnten, Kundendaten oder ähnliche Informationen zu verwalten, sind hier von untergeordneter Bedeutung. # Grundlagen & Architektur von strapi Source: https://dokumentation.websale.de/strapi-cms/grundlagen-architektur-von-strapi Einführung in strapi als Headless-CMS für WEBSALE: API-First-Ansatz, Zusammenspiel von Content-Type Builder und Content-Manager sowie Auslieferung. Auf dieser Seite werden die grundlegenden Konzepte und die Architektur von strapi erklärt. Ziel ist es, ein Verständnis dafür zu schaffen, wie strapi als Headless-CMS aufgebaut ist, welche Rolle der API-First-Ansatz spielt und wie Inhalte aus Strapi in den WEBSALE Shop ausgeliefert werden. Damit dient die Seite als Basis, um die weiteren Bereiche der Dokumentation (insbesondere Content-Typen, Komponenten und die Pflege von Inhalten) besser einordnen und sicher anwenden zu können. ## Grundlagen von strapi ### Verständnis der Strapi Architektur In strapi gibt es zwei Hauptbereiche, die für die Verwaltung und Strukturierung von Inhalten zuständig sind: der **Content-Manager** und der **Content-Type Builder**. Diese Bereiche ergänzen sich und bieten zusammen ein leistungsstarkes Werkzeugset für Content-Management und -Design. ## Content-Type Builder & Content-Manager ### Content-Type Builder: Definition von Strukturen und Komponenten Dieser Bereich wird verwendet, um die Strukturen zu definieren, in denen die Inhalte später eingegeben werden. Hier wird festgelegt, welche Felder und Datentypen die Inhalte haben sollen und die Komponenten erstellt, die dann im Content-Manager gefüllt werden. * **Strukturen definieren**: Der Content-Type Builder wird genutzt, um die Schemata für Sammlungen und Einzel-Einträge zu erstellen und zu bearbeiten. Diese Schemata bestimmen, welche Datenfelder und Datentypen verfügbar sind und wie die Eingabemasken im Content-Manager aussehen. * **Komponenten gestalten**: Eine weitere wichtige Funktion des Content-Type-Builders ist das Erstellen von wiederverwendbaren Komponenten. Diese Komponenten können in verschiedenen Teilen des Projekts genutzt werden und fördern dadurch die Konsistenz und Wiederverwendbarkeit in der Entwicklung. ### Content-Manager: Verwaltung von Inhalten Hier werden die Inhalte, die in einem Strapi-Projekt erstellt und gepflegt werden, direkt verwaltet. Dies ist der Ort, an dem Benutzer tatsächlich Inhalte wie Texte, Bilder und andere Medien hinzufügen, die auf der Storefront angezeigt werden. * **Inhalte verwalten**: Im Content-Manager werden alle Inhalte wie Texte, Bilder, Videos und andere Medien, die direkt auf der Storefront sichtbar sind, verwaltet. Benutzer können hier neue Inhalte erstellen, bestehende bearbeiten oder nicht mehr benötigte Inhalte löschen. * **Daten organisieren**: Der Content-Manager ermöglicht das systematische Organisieren von Inhalten in Sammlungen und Einzel-Einträgen. Diese Struktur hilft, Inhalte leichter auffindbar und verwaltbar zu machen und unterstützt eine klare Hierarchie und Ordnung innerhalb des Systems. ### Zusammenspiel von Content-Manager und Content-Type Builder Der Content-Manager und der Content-Type-Builder arbeiten Hand in Hand: * **Vom Builder zum Manager**: Im Content-Type-Builder erstellte Strukturen und Komponenten dienen als Grundlage für die Inhaltsverwaltung im Content-Manager. Dies sichert eine kohärente Datenhandhabung und effiziente Content-Verwaltung. * **Anpassungsfähigkeit und Dynamik**: Durch die flexible Struktur des Content-Type Builders können Anpassungen vorgenommen werden, die dann im Content-Manager reflektiert werden, ohne dass Inhalte verloren gehen oder umständlich neu erstellt werden müssen. ## Sammlungen, Einzel-Einträge und Komponenten ### Sammlungen **Sammlungen** in Strapi sind Strukturen, die dazu dienen, mehrere ähnliche Daten unter einem Dach zu verwalten. Sie eignen sich hervorragend, um Inhaltsseiten, mehrere Stellenanzeigen oder auch Blogartikel zu organisieren. Eine Sammlung fungiert somit als zentraler Punkt, dem sie ähnliche Inhalte oder Elemente unterordnen können. Sammlungen stehen sowohl unter dem Content-Manager, wie auch dem Content-Type-Builder zur Verfügung. Mehr Informationen zu Sammlungen gibt es [hier](/strapi-cms/komponenten-sammlungen-in-strapi). ### Einzel-Einträge **Einzel-Einträge** sind spezifische Inhalts-Elemente, die nicht unbedingt Teil einer wiederholbaren Sammlung sind. Sie können für spezielle Seiten oder spezifische Inhaltsblöcke verwendet werden, wie zum Beispiel ein Banner oder ein Produktslider auf der Startseite. Einzel-Einträge stehen sowohl unter dem Content-Manager, wie auch dem Content-Type-Builder zur Verfügung. Mehr Informationen zu Einzel-Einträgen gibt es [hier](/strapi-cms/komponenten-sammlungen-in-strapi). ### Content-Typen zum Erstellen neuer Sammlungen & Einzel-Einträge Content-Typen sind die Bausteine für die Strukturierung von Inhalten innerhalb von Strapi. Sie definieren, wie Daten in Sammlungen und Einzel-Einträgen organisiert sind. Neue Content-Typen und somit neue Inhalte unterhalb von Sammlungen und Einzel-Einträgen werden im Content-Type Builder erstellt. Zum Anlegen neuer Content-Typen wird die Unterstützung eines WEBSALE-Mitarbeiters aus der Systemadministration benötigt. Dieser muss die neuen Content-Typen in der Konfiguration des Strapi-Connectors hinterlegen. ### Komponenten **Komponenten** in Strapi sind wiederverwendbare Bausteine, die in verschiedenen Teilen des Projekts genutzt werden können, um Inhalte konsistent und effizient zu gestalten. Mehr Informationen zu Komponenten gibt es [hier](/strapi-cms/komponenten-sammlungen-in-strapi). ## SEO-Meta-Daten für CMS-Seiten (Meta-Info-Plugin) Für CMS-Seiten steht im Standard das Meta-Info-Plugin zur Verfügung. Es ist auf jeder CMS-Seite vorhanden und stellt dort feste, vorgegebene Felder für die SEO-Angaben bereit: SEO-URL, Meta-Title, Meta-Description und Robots. Diese Felder müssen nicht selbst angelegt werden. Sie gehören nicht zu den frei gestaltbaren Content-Typen, sondern werden vom Plugin verwaltet. Dadurch sind sie auf jeder Seite identisch vorhanden und können beim Bearbeiten der Content-Typen nicht versehentlich verändert oder gelöscht werden. So ist sichergestellt, dass jede in Strapi angelegte Seite zuverlässig über eine SEO-URL verfügt und darüber aufrufbar ist. Die eingetragenen Werte werden an den Shop übergeben. Der Shop setzt Meta-Title und Meta-Description über denselben internen Weg wie bei Kategorie- und Produktseiten. Sie stehen deshalb wie gewohnt im Template über die Funktionen [\$wsViews.metaTitle()](https://dokumentation.websale.de/frontend/referenz/module/wsviews#\$wsviews-metatitle) und [\$wsViews.metaDescription()](https://dokumentation.websale.de/frontend/referenz/module/wsviews#\$wsviews-metadescription) bereit. Im Template erscheinen alle Robots-Angaben gesammelt unter [\$wsViews.current.robotOptions](https://dokumentation.websale.de/frontend/referenz/module/wsviews#\$wsviews-current-robotoptions). Der Shop setzt diese Angaben, er gibt sie nicht von sich aus im HTML aus. Für Meta-Title und Meta-Description erledigt das üblicherweise das Basis-Template. Die Robots-Angaben und die Alternativsprachen (`hreflang`) rendert das Basis-Template im Auslieferungszustand dagegen nicht. Wer sie braucht, muss sie im CMS-Seitentemplate selbst ausgeben, siehe [Template Theme](/frontend/die-basics/template-theme#cms-seitentemplate). Der Konfigurationsknoten [`seoMetaData`](/konfiguration/seometadata-meta-daten-seo-texte) und dort insbesondere `viewSchemes` betrifft die SEO-Texte statischer Views. Für CMS-Seiten wird er nicht ausgewertet. Deren SEO-Angaben kommen ausschließlich aus dem Meta-Info-Plugin. Weiterführende Informationen: * Die Bedeutung der einzelnen SEO-Felder ist unter [Komponenten & Sammlungen in strapi](/strapi-cms/komponenten-sammlungen-in-strapi) im Abschnitt „Meta-Information“ beschrieben. * Die Pflege der Meta-Angaben je Seite ist unter [Inhalte anpassen in strapi](/strapi-cms/inhalte-anpassen-in-strapi) anhand von Beispielen dargestellt. * Wie der Shop aus diesen Angaben eine aufrufbare Seite macht, steht im nächsten Abschnitt. ## Auslieferung von CMS-Seiten in den Shop Statische Inhaltsseiten (beispielsweise AGB, Impressum, Zahlungsarten, „Über uns") werden in strapi gepflegt und als JSON-Dokumente in den Shop übertragen. Der Shop registriert dafür eigene SEO-URLs und rendert alle diese Seiten mit einem Template. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} strapi (Redaktion) │ Content-Typen + Meta-Info-Plugin (SEO-Felder) ▼ websale-sync ──► Dateigruppe "system" json//index-mapping.json ← Seitenverzeichnis json//<…>/.json ← ein Dokument je Seite │ ├─► SEO-URL-Generator registriert die SEO-URLs (View-Controller "CmsPage") │ └─► Shop Aufruf der SEO-URL → lädt das Dokument → rendert cms_tpl.htm Das Dokument steht im Template als $wsCmsPage bereit ``` Damit eine Seite erscheint, müssen zwei Dinge zusammenpassen: die SEO-URL muss registriert sein (das macht der SEO-URL-Generator anhand des Seitenverzeichnisses) und das Seitendokument muss im Objektspeicher liegen. Fehlt eines von beidem, liefert der Shop einen 404-Fehler. ### Der SEO-URL-Generator SEO-URLs entstehen nicht beim Seitenaufruf, sondern in einem eigenen Prozess. Der SEO-URL-Generator (Programm `seogenerator`) durchläuft dabei die Ressourcen eines Subshops durch und schreibt für jede eine SEO-URL in den URL-Bestand des Shops. Er ist nicht CMS-spezifisch. Dieselbe Mechanik registriert auch die URLs von Produkten und Kategorien. Jeder Subshop wird separat verarbeitet. ### Ablage in der Dateigruppe `system` Die Pfade sind fest verdrahtet und nicht konfigurierbar. Es handelt sich um dieselbe Dateigruppe, die Templates über die Ladeoption `source: "system"` erreicht wird (siehe [\$wsExternalData](/frontend/referenz/module/wsexternaldata)). | **Datei** | **Pfad innerhalb der Dateigruppe `system`** | | ----------------- | ------------------------------------------- | | Seitenverzeichnis | `json//index-mapping.json` | | Seitendokument | `json//` | * `` ist die ID des Subshops, beispielsweise `deutsch`, `english`, `francais`. Jeder Subshop hat seinen eigenen Ordner und liest ausschließlich sein eigenes Seitenverzeichnis. * Der **Name** der Verzeichnisdatei ist über `cmsTemplates.mappingFile` konfigurierbar (Standard `index-mapping.json`). Der Ordner `json/` ist es nicht. * Die Ordnerstruktur unterhalb von `json//` ist frei. Üblich ist die strapi-Struktur, beispielsweise `collections/contentpage/jyllb6ubw0dj62vndr0lh7z1.json`. Der Dateiname hat keine Bedeutung. Er hat keinen Einfluss auf die URL der Seite. Diese steht ausschließlich im Feld `url` im Seitenverzeichnis bzw. in `meta.url` des Dokuments. ### Welche URL gehört zu welcher Datei Das Seitenverzeichnis beantwortet diese Frage: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "mappings": [ { "url": "Zahlungsarten", "file": "collections/contentpage/jyllb6ubw0dj62vndr0lh7z1.json", "subshop": "deutsch", "stage": "live" }, { "url": "AGB", "file": "collections/contentpage/agb1.json" } ] } ``` | **Feld** | **Pflicht** | **Bedeutung** | | --------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | `url` | ja | Die aufrufbare URL der Seite, **ohne** führenden Schrägstrich. Ist sie leer oder `null`, wird der Eintrag ignoriert. | | `file` | ja | Pfad des Dokuments relativ zu `json//`. Ist er leer, wird der Eintrag ignoriert. | | `subshop` | nein | Subshop, dem die Seite gehört. Leer oder fehlend = gilt für jeden Subshop. Steht hier ein anderer Subshop als der lesende, wird der Eintrag übersprungen. | | `stage` | nein | `live` oder leer/fehlend = wird veröffentlicht. Jeder andere Wert (beispielsweise `draft` oder `preview`) wird übersprungen. | Bei jedem Durchlauf des SEO-URL-Generators werden die URLs aller passenden Einträge neu registriert und alle bereits registrierten CMS-URLs entfernt, die sich nicht mehr im Verzeichnis befinden. Dadurch verschwindet eine gelöscht oder auf `stage:draft` gesetzte Seite beim nächsten Erzeugen der SEO-URLs von selbst. Das Aufräumen findet nur im vollständigen Durchlauf statt. Wird über `POST seo/urls/reset` eine einzelne Seite neu registriert, werden keine URLs entfernt. Kann das Seitenverzeichnis nicht gelesen werden, bricht der Lauf vorzeitig ab und es werden weder neue URLs registriert noch alte entfernt. Nicht zu verwechseln mit der Option „nicht mehr genutzte URLs löschen" (`deleteOld`) beim Anstoßen des Laufs: Das Entfernen verschwundener CMS-Seiten passiert unabhängig davon. #### Hinweise zur URL Der Wert aus `url` wird als fertiger Pfad übernommen. Der Shop fügt lediglich einen Schrägstrich davor hinzu und ergänzt bei Bedarf den abschließenden Schrägstrich. Das hat mehrere Konsequenzen: * **Kein führender Schrägstrich.** Der Shop setzt ihn selbst. Ein Wert wie `"/AGB"` führt zu einer doppelten Trennung (`//AGB`) und damit zu einer nicht erreichbaren Seite. * **Der abschließende Schrägstrich** wird gemäß Shop-Konfiguration (`urls.urls.alwaysEndWithSlash`) automatisch ergänzt. * **Keine Zeichensatz-Prüfung und keine Normalisierung.** Großbuchstaben sind ausdrücklich üblich (`AGB`, `Zahlungsarten`). * **Die URL-Aufbereitung des Shops greift hier nicht.** Von den Einstellungen unter [urls.urls](/konfiguration/urls-url-webadressen) wirken auf CMS-URLs nur `active` und `alwaysEndWithSlash` (sowie `suffixSeparator` im Kollisionsfall). `lowercase`, `wordSeparator` und die Zeichen-`mappings` für Umlaute werden **nicht** angewendet – anders als bei Kategorie- und Produkt-URLs. Aus `AGB` wird also auch bei `lowercase: true` der Pfad `/AGB`. * **Die URL wird beim Aufruf exakt verglichen**, also inklusive Groß- und Kleinschreibung. `/agb` findet eine als `AGB` registrierte Seite nicht. * **Sonderzeichen und Leerzeichen müssen bereits kodiert sein.** Der Wert wird als bereits kodierter Pfad behandelt und dekodiert. Sauberer ist es, sie in strapi zu vermeiden. * **Bereits im Admin Interface manuell gesetzte URLs gewinnen.** Existiert für eine Seite eine manuell gesetzte URL, wird der Wert aus dem Seitenverzeichnis stillschweigend ignoriert , ohne Logmeldung. Eine geänderte `url` bleibt dann wirkungslos. * **Bei einer Pfadkollision** hängt der Shop `suffixSeparator` plus eine Zahl an, statt die Registrierung abzubrechen. Die Seite ist dann unter einer unerwarteten URL erreichbar, und es gibt dazu keine Logmeldung. Ältere Pfade derselben Seite werden per 301 auf den aktuellen Pfad umgeleitet. Weil der Shop nichts normalisiert, muss die URL bereits in strapi so gepflegt werden, wie sie im Browser stehen soll. Das ist Absicht: Seitennamen wie `AGB` sollen nicht durch eine automatische Kleinschreibung verändert werden. ### Das Seitendokument Jedes Dokument hat die gleiche äußere STruktur, die sogenannte "Hülle": `contentType`, `meta` und `fields`. Es handelt sich um dieselbe Hülle wie im schema-Format der Sync-Middleware, das unter [Migration der strapi-Datenstruktur (Version 5)](/strapi-cms/migration-der-strapi-datenstruktur-v5#das-schema-format-im-detail) ausführlich beschrieben ist. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "contentType": "api::contentpage.contentpage", "meta": { "id": 92, "documentId": "jyllb6ubw0dj62vndr0lh7z1", "locale": "de", "createdAt": "2026-06-26T08:00:00.000Z", "updatedAt": "2026-07-16T09:00:00.000Z", "publishedAt": "2026-07-16T09:03:00.000Z", "url": "Zahlungsarten", "metaTitle": "Zahlungsarten", "metaDescription": "Beschreibung zu Zahlungsarten", "robots": ["noindex", "nofollow"], "hreflang": [ { "language": "fr-fr", "url": "myshop.fr/paiement", "subshopId": "francais", "default": false } ] }, "fields": [ { "name": "Markup", "type": "richtext", "value": "AGB Content" }, { "name": "content", "type": "dynamiczone", "value": [ { "component": "elemente.ws-markup", "id": 96, "fields": [ { "name": "FullWidth", "type": "boolean", "value": false } ] } ] } ] } ``` | **Ebene** | **Inhalt** | **Wird vom Shop …** | | ------------- | ------------------------------------------------------------------ | -------------------------------------------------------------- | | `contentType` | Content-Typ der Seite | gelesen, aber nicht ausgewertet | | `meta` | strapi-Verwaltungsdaten plus SEO-Block | teilweise ausgewertet, siehe unten | | `fields` | Die redaktionellen Inhalte, Struktur frei nach Kunden-Modellierung | unverändert durchgereicht. Der Shop interpretiert hier nichts. | Der Grundsatz hierbei lautet: Die Hülle ist fest, der Inhalt ist frei.
    Der Shop garantiert lediglich die Auswertung des SEO-Blocks. Wie `fields` aussieht, bestimmt allein die Modellierung der Content-Typen in strapi. Wie es dargestellt wird, bestimmt allein das Template. Es gibt keine vom Shop vorgegebenen Inhaltsblock-Typen. Der Shop kennt keine festen Bausteine wie "Übeschrift" oder "Bild" mit garantierter Bedeutung. Welche Feldnamen und Komponenten es gibt, ergibt sich aus der strapi-Modellierung des jeweiligen Shops und ihre Darstellung ist vollständig Aufgabe des Templates. #### Der SEO-Block in `meta` Diese Felder wertet der Shop aus: | **Feld** | **Typ** | **Pflicht** | **Wirkung** | | ----------------- | ----------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `url` | Text | ja für `seo/urls/reset` | Die URL der Seite, ohne führenden Schrägstrich. Im vollständigen Lauf zählt der Wert aus dem Seitenverzeichnis; beim Zurücksetzen einer einzelnen URL über `POST seo/urls/reset` dagegen dieser Wert. Fehlt er dort, wird keine SEO-URL erzeugt. Beide Werte sollten übereinstimmen. | | `metaTitle` | Text | empfohlen | Wird als Meta-Title der Seite gesetzt (Browser-Tab, Suchergebnis). | | `metaDescription` | Text | optional | Wird als Meta-Description gesetzt. | | `robots` | Liste von Texten | optional | Jeder Eintrag wird den Robots-Angaben der Seite hinzugefügt, beispielsweise `["noindex", "nofollow"]`. Einträge, die kein Text sind, werden stillschweigend übersprungen. | | `publishedAt` | Zeitstempel oder `null` | ja, für die öffentliche Sichtbarkeit | Steuert Entwurf/Veröffentlicht, siehe unten. | Alle weiteren `meta`-Felder (`id`, `documentId`, `locale`, `createdAt`, `updatedAt`) sind strapi-Verwaltungsdaten. Sie werden nicht ausgewertet, stehen dem Template aber zur Verfügung. `meta.hreflang` ist Teil der Hülle und steht im Template zur Verfügung, wird aber nicht automatisch in die hreflang-Angaben des Shops übernommen. `$wsViews.current.getHreflangAutomatic()` liefert für CMS-Seiten nichts. Wer Alternativsprachen ausgeben will, muss sie im Template selbst rendern, siehe [Template Theme](/frontend/die-basics/template-theme#cms-seitentemplate). ### Entwurf und Veröffentlichung Es gibt zwei voneinander unabhängige Schalter: 1. **`stage`** im Seitenverzeichnis entscheidet, ob die URL überhaupt entsteht. `live` oder leer → die URL wird registriert. Alles andere → kein Eintrag, die Seite ist nicht adressierbar. 2. **`meta.publishedAt`** im Dokument entscheidet, ob die Seite ausgeliefert wird. | **`publishedAt`** | **Öffentlicher Aufruf** | **Mit aktiver Testmodus-Session** | | ------------------- | ----------------------- | ---------------------------------- | | Zeitstempel gesetzt | Seite wird ausgeliefert | Seite wird ausgeliefert | | `null` oder fehlend | 404 | Seite wird ausgeliefert (Vorschau) | Entwürfe lassen sich also im Shop vorab ansehen, indem der Testmodus aktiviert wird, genau wie bei anderen Vorschau-Inhalten. Siehe [Testmodi des Shops ein-/ausschalten](/testmodi-des-shops-ein-ausschalten). Es wird nur geprüft, ob ein Wert vorhanden ist, nicht, ob der Zeitpunkt in der Vergangenheit liegt. Ein `publishedAt` in der Zukunft veröffentlicht die Seite sofort. Eine zeitgesteuerte Veröffentlichung über den Shop ist damit nicht möglich. Sie muss auf der strapi-Seite erfolgen, da strapi das Feld `publishedAt` erst beim Veröffentlichen setzt. ### Konfiguration Der Konfigurationsknoten `cmsTemplates` liegt im Bereich `content`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "cmsTemplates": { "template": "cms_tpl.htm", "mappingFile": "index-mapping.json" } } ``` | **Parameter** | **Standard** | **Bedeutung** | | ------------- | -------------------- | ---------------------------------------------------------------------------------- | | `template` | `cms_tpl.htm` | Template, mit dem CMS-Seiten gerendert werden. Pfad relativ zu `templates/views/`. | | `mappingFile` | `index-mapping.json` | Name der Verzeichnisdatei in `json//` | Der Knoten ist ein Singleton und je Subshop überschreibbar. Alle Details unter [content.cmsTemplates](/konfiguration/content-katalog-kategorien-produkte#content-cmstemplates-cms-seiten). ### Wenn eine CMS-Seite nicht erscheint | **Symptom** | **Wahrscheinliche Ursache** | **Prüfen** | | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Die Seite liefert 404 | Die SEO-URL ist nicht registriert. | Steht die Seite mit `url` und `file` im Seitenverzeichnis? Passt `subshop` zum aufgerufenen Subshop? Steht `stage` auf `live` oder ist es leer? Sind SEO-URLs überhaupt aktiv (`urls.urls.active`)? Lief der SEO-URL-Generator seit der letzten Änderung? | | Keine einzige CMS-Seite ist erreichbar | `cmsPage` fehlt in `urls.urls.generate`, oder es lief noch kein Lauf. | [Der SEO-URL-Generator](#der-seo-url-generator) | | Die Seite liefert 404, obwohl die URL registriert ist | Das Dokument fehlt, ist leer oder nicht lesbar, oder es ist ein Entwurf. | Liegt die Datei unter `json//`? Ist `meta.publishedAt` gesetzt? Ist die Datei gültiges JSON (Log-Code `cmsTemplates.jsonParseError`)? | | Die Seite ist unter `//AGB` bzw. gar nicht erreichbar | `url` enthält einen führenden Schrägstrich. | Führenden Schrägstrich aus `url` entfernen. | | Die Seite ist unter einer URL mit angehängter Zahl erreichbar | Der Pfad kollidiert mit einer bereits registrierten URL. | Kollidierende URL im Admin Interface bzw. im Seitenverzeichnis auflösen. | | Eine geänderte `url` wirkt nicht, die Seite bleibt unter der alten Adresse | Für die Seite ist im Admin Interface eine URL manuell gesetzt. Die wird nicht überschrieben, und es gibt dazu keine Logmeldung. | Manuelle URL der Ressource im Admin Interface prüfen, siehe [API-Referenz SEO-URLs](/schnittstellen/admin-interface-api/api-referenz-seo-urls). | | Eine gelöschte Seite ist weiterhin erreichbar | Es lief kein vollständiger Lauf, oder der Lauf brach am Seitenverzeichnis ab. | Log auf `cmsTemplates.generateNoMapping` und `cmsTemplates.generateMappingParseError` prüfen. | | Die Seite erscheint, aber ohne Inhalte aus `fields` | Feldname oder Komponenten-Name im Template passt nicht zur strapi-Modellierung. | [Template Theme](/frontend/die-basics/template-theme#cms-seitentemplate) | Die Meldungen des SEO-URL-Generators und des Seitenaufrufs sind im [Log-Manager](/admin-interface/logmanager-logs) über diese Codes auffindbar: | **Log-Code** | **Bedeutung** | | ---------------------------------------- | ------------------------------------------------------------------------------- | | `cmsTemplates.generateNoMapping` | Das Seitenverzeichnis konnte nicht gelesen werden. Der Lauf bricht ab. | | `cmsTemplates.generateMappingParseError` | Das Seitenverzeichnis ist kein gültiges JSON. | | `cmsTemplates.generateSkippedMapping` | Ein Eintrag wurde übersprungen. Die Meldung nennt `url`, `stage` und `subshop`. | | `cmsTemplates.generateSingleReadError` | Bei `seo/urls/reset` war das Dokument nicht lesbar. | | `cmsTemplates.generateSingleParseError` | Bei `seo/urls/reset` war das Dokument kein gültiges JSON. | | `cmsTemplates.generateSingleNoUrl` | Bei `seo/urls/reset` fehlte `meta.url` im Dokument. | | `cmsTemplates.jsonParseError` | Beim Seitenaufruf war das Dokument kein gültiges JSON. Der Shop liefert 404. | *** ## Medienbibliothek Strapi verfügt über eine integrierte Medienbibliothek, die eine zentrale Verwaltung von Medien wie Bildern, PDFs und anderen Dateien ermöglicht. Alle hochgeladenen Bilder und Dateien werden in der Medienbibliothek gespeichert und können von dort aus verwaltet werden. Dies umfasst das Löschen, Ersetzen oder erneute Verwenden von Medien in verschiedenen Teilen des Strapi-Projekts. ### Hochladen von Medien Medien können entweder direkt in die Medienbibliothek hochgeladen oder während der Pflege von Inhalten hinzugefügt werden. Wenn beim Bearbeiten von Inhalten Medien benötigt werden, kann auf die Medienbibliothek zurückgegriffen werden. Hier besteht die Möglichkeit, bereits hochgeladene Dateien auszuwählen oder neue Dateien hinzuzufügen. ### Automatische Bildkonvertierung Strapi verfügt über einen eingebauten Konverter, der die hochgeladenen Bilder automatisch komprimiert, um die Ladezeiten zu verbessern und den Speicherbedarf zu optimieren. Zusätzlich kommt der WEBSALE Bildkonverter zum Einsatz, der Bilder in das SourceFormat und das WebP-Format umwandelt. Diese Formate bieten verbesserte Kompressionsraten und sind für die Web-Nutzung optimiert. ### Template-Integration Der Template-Manager definiert innerhalb des Templates, welches Bild in welchem Format verwendet wird. Neue Bilder und Medienelemente, die zur Medienbibliothek hinzugefügt werden, müssen daher entsprechend den Vorgaben vom Template-Manager im Template platziert und konfiguriert werden. Weitere Informationen für Template-Manager befinden sich [hier](/strapi-cms/templates-fur-strapi-inhalte-anpassen#bildformate-definieren). ## Strapi für Subshops erweitern ### Neue Sprache anlegen * Einstellungen → Internationalisierung * “Neue Sprache hinzufügen” * Sprache auswählen. * Anzeigenamen **nicht** ändern. * Locale-ID notieren / kopieren. Beispielsweise “Französisch (**fr**)” - **fr** wäre hier die Locale-ID. * Speichern. ### Sprache einem Subshop zuweisen * Content-Manager → Konfiguration * “+ Eintrag hinzufügen” wählen oder einen bestehenden bearbeiten. * Unter “WEBSALE Subshop ID” kann nun eine kommaseparierte Liste an Subshop-IDs eingetragen werden. * Unter “Strapi Locale ID” muss die im vorherigen Schritt kopierte “Locale-ID” eingefügt werden. * Im Anschluss speichern. Der WEBSALE Strapi Connector beachtet nun automatisch die neue Sprache.
    Content, der im Content-Manager für diese Sprache gepflegt wird, wird auf dem Shopserver in die Verzeichnisse für Subshops abgelegt. Jeder Wert (kommasepariert) stellt einen Subshop-Ordner dar.
    # Inhalte anpassen in strapi Source: https://dokumentation.websale.de/strapi-cms/inhalte-anpassen-in-strapi Inhalte im strapi CMS pflegen: Standardseiten bearbeiten, neue Beiträge anlegen sowie Unterschiede zwischen Speichern, Veröffentlichen und Testen. Auf dieser Seite wird beschrieben, wie Inhalte im Strapi CMS im WEBSALE-Kontext gepflegt und angepasst werden. Dazu gehören das Bearbeiten bestehender Inhalte, das Anlegen neuer Inhalte sowie die grundlegenden Unterschiede zwischen Speichern und Veröffentlichen – inklusive Hinweisen zum Vorab-Testen. Anhand praxisnaher Beispiele (z. B. Inhaltsseiten, Slider, Product-Slider, Product-Teaser) zeigt die Dokumentation typische Arbeitsschritte im Content-Manager und hilft dabei, Änderungen sicher umzusetzen, ohne dass dafür Entwicklungskenntnisse erforderlich sind. *** ## Inhalte anpassen ### Überblick über die standardmäßig ausgelieferten strapi Inhalte Strapi ermöglicht die Verwaltung einer Vielzahl von Inhaltsseiten, die für die grundlegende Funktionalität und Informationsvermittlung des Online-Shops essentiell sind. Im Standardumfang unserer Shopsoftware werden folgende Seiten ausgeliefert: * **Startseite**: Die zentrale Anlaufstelle für Besucher des Shops. * **Impressum**: Wichtige rechtliche Informationen über den Betreiber des Shops. * **Wir über uns**: Informationen über das Unternehmen, seine Geschichte und seine Werte. * **AGB (Allgemeine Geschäftsbedingungen)**: Die rechtlichen Grundlagen des Einkaufs in deinem Shop. * **Datenschutz**: Erläuterungen zum Umgang mit Nutzerdaten und Datenschutzbestimmungen. * **Kontaktformular**: Eine Seite, die es den Kunden ermöglicht, direkt Kontakt aufzunehmen. Diese Seiten bilden das Grundgerüst für die rechtliche und personelle Darstellung des Online-Shops gegenüber den Kunden. *** ## Speichern vs. Veröffentlichen In Strapi ist die Handhabung von Inhalten durch die Funktionen "Speichern" und "Veröffentlichen" getrennt, um eine flexible Content-Verwaltung zu ermöglichen. Diese Funktionen beeinflussen, wie Inhalte bearbeitet und für den Besucher sichtbar gemacht werden. ### Speichern * Das Speichern von Inhalten in Strapi ermöglicht es, Änderungen an einer Seite oder einem Beitrag zu machen und diese Änderungen intern zu sichern, ohne dass sie sofort für die Öffentlichkeit sichtbar sind. * Wenn eine Seite oder ein Inhalt bereits veröffentlicht wurde und Änderungen vorgenommen werden, werden diese durch das Speichern sofort öffentlich sichtbar. Das bedeutet, dass alle gespeicherten Änderungen an veröffentlichten Inhalten direkt auf der Live-Seite aktualisiert werden. ### Veröffentlichen * Das Veröffentlichen macht die Inhalte für alle sichtbar. * Wird eine Seite, die zuvor veröffentlicht wurde, auf “unveröffentlicht” gestellt und anschließend Änderungen vorgenommen und gespeichert, so verbleiben diese Änderungen intern, ohne für die Öffentlichkeit sichtbar zu sein. Diese gespeicherten Änderungen befinden sich im Entwurfsstatus. ### Vorab testen Trotz der öffentlichen Sichtbarkeit von Änderungen nach dem Speichern, bietet Strapi die Möglichkeit, Änderungen im [Testmodus](/frontend/referenz/module/wstestmode) zu sehen, bevor sie endgültig live geschaltet werden. Dies ermöglicht eine letzte Überprüfung, um sicherzustellen, dass alles wie gewünscht funktioniert. *** ## Anpassen von Inhaltsseiten am Beispiel der Impressums-Seite Um Änderungen am Inhalt einer Inhaltsseite vorzunehmen, muss zuerst die Seite ausgewählt werden, um die es geht. ### Seite zum Bearbeiten auswählen * Navigiere im linken Seitenmenü zu **Content-Manager**. * Wähle innerhalb von **Sammlungen** den Unterpunkt **Inhaltsseiten**. Sollte dieser nicht bereits ausgewählt sein, wähle ihn aus, um die Inhaltsseiten zu bearbeiten. * Dort wird eine Übersicht der hinterlegten Inhaltsseiten angezeigt * Wähle die Seite **Impressum** oder eine andere Seite, die bearbeiten werden soll. Nach Auswahl der Seite, wird als Überschrift der **Name des Templates** - in diesem Falle also **tpl\_imprint** - angezeigt. Diese Information ist dann nützlich, wenn das Design dieser Seite grundsätzlich über das [Template](/frontend/die-basics/template-theme) geändert werden muss. ### Öffnen der Bearbeitungsansicht * Nach der Auswahl öffnet sich die Bearbeitungsseite für das Impressum * Die Bearbeitungsseite ist in verschiedene Abschnitte unterteilt, um die Orientierung zu erleichtern: * Abschnitt 01: Template Name und Meta-Informationen * Abschnitt 02: Seiteninhalt * Abschnitt 03: Testmodus ### Bearbeitung der Seitendetails * **Template-Name**: Ändere den Namen nur, wenn das Template gewechselt wurde. Stelle sicher, dass das entsprechende Template auf dem Server vorhanden ist. * **Meta-Angaben**: Optimiere die SEO-Angaben (Meta Title, Meta Beschreibung, Meta-Robots) zur Verbesserung der Auffindbarkeit in Suchmaschinen. * **SEO-URL**: Gib die URL an, unter der die Seite später aufgerufen werden kann. ### Bearbeitung des Seiteninhalts * **Öffne eine der Inhalts-Komponenten**, die standardmäßig für den Seiteninhalt der Impressumseite verwendet werden. Passe den Text nach Bedarf an. * Um die Seite um weitere Inhalte zu erweitern, können **zusätzliche Komponenten** hinzufügt werden: * Klicke auf das Symbol (+) neben oder unter der bestehenden Komponente, um „Content eine Komponente hinzuzufügen“. * Wähle aus den verfügbaren Komponenten aus, die für die Strapi-Instanz konfiguriert wurden. Dies kann von Medienelementen und Formularen bis zu speziellen Layout-Komponenten reichen, die die Funktionalität und das visuelle Erlebnis der Seite verbessern. * Nach dem Hinzufügen, öffnet sich die Komponente automatisch und es kann mit der Bearbeitung begonnen werden. ### Speichern und Testmodus * **Testmodus-Optionen**: Vor dem speichern muss am Ende der Seite über die Auswahl "JA / NEIN" entschieden werden, ob die Änderungen im [Testmodus](/frontend/referenz/module/wstestmode) oder im Livemodus angezeigt werden sollen. *** ## Anpassen von einem Bilder-Slider am Beispiel der Startseite ### Seite zum Bearbeiten auswählen * Navigiere im linken Seitenmenü zu **Content-Manager**. * Wähle innerhalb von **Sammlungen** den Unterpunkt **Inhaltsseiten**. Sollte dieser nicht bereits ausgewählt sein, wähle ihn aus, um die Inhaltsseiten zu bearbeiten. * Dir wird eine Übersicht der hinterlegten Inhaltsseiten angezeigt * Wähle die Seite **Über uns** oder eine andere Seite, die bearbeitet werden soll. ### Bearbeitung der Seitendetails * **Template-Name**: Ändere den Namen nur, wenn das Template gewechselt wurde. Stelle sicher, dass das entsprechende Template auf dem Server vorhanden ist. * **Meta-Angaben**: Optimiere die SEO-Angaben (Meta Title, Meta Beschreibung, Meta-Robots) zur Verbesserung der Auffindbarkeit in Suchmaschinen. * **SEO-URL**: Gib die URL an, unter der die Seite später aufgerufen werden kann. ### Allgemeine Optionen für den Slider * **Anzeige über die gesamte Bildschirmbreite**: Abhängig vom Storefront-Design des Shops kann man wählen, ob der gesamte Slider über die gesamte Bildschirmbreite angezeigt werden soll. Diese Einstellung gilt für den kompletten Slider und nicht für einzelne Slides. ### Slides hinzufügen * **Slider-Komponente öffnen**: Öffne die "Slider" Komponente auf der Bearbeitungs-Seite * **Slides definieren**: Die einzelnen Elemente der Slider-Komponenten werden als "Slides" bezeichnet. Ein "Slide" ist jeweils ein Teil des Sliders. Zeitgesteuert oder durch eine Aktion des Shopbesuchers wird später durch die einzelnen "Slides" geblättert. * **Neuen Slide hinzufügen**: Drücke das Feld mit dem (+), um einen neuen Slide zu ergänzen. * **Anzeigestatus festlegen**: Über "Anzeigestatus" mit der Auswahl "Ja" wird der Slide im Slider angezeigt. Mit der Auswahl "Nein" wird der Slide nicht angezeigt. So können Slides auch vorübergehend oder nur für eine bestimmte Zeit ausgeblendet - und später wieder eingeblendet werden. * **Beschreibung hinzufügen**: Vergib eine Beschreibung für diesen Slide, die zur besseren Übersicht im CMS dient. * **Link hinzufügen**: Im Feld "Link" kann eine Verlinkung gesetzt werden. Beim Klick auf den "Slide" wird der Besucher zu dieser Verlinkung weitergeleitet. Hierfür stehen verschiedene "Linktypen" zur Verfügung: * **Product**: Gib eine Produktnummer ein, um den Besucher zur Produktdetailansicht dieses Produktes weiterzuleiten. * **Category**: Gib einen Kategorie-Index ein, um den Besucher zur Kategorieseite dieser Kategorie weiterzuleiten. * **Internal**: Gib spezifische Pfade oder Routen an, die zu anderen Seiten oder Ressourcen innerhalb deines Online-Shops führen. * **URL**: Gib eine URL an, um den Besucher zu dieser URL weiterzuleiten. * **Bilder zuweisen**: Innerhalb von "Bilder" klicke auf das Feld mit dem "(+)". * Es erscheinen sechs weitere Felder, die jeweils das anzuzeigende Bild für den entsprechenden Viewport darstellen (XS bis XXL, von Smartphones bis zu Wide-Screens): * **XS / SM:** Smartphones\ **MD / LG:** Tablets und kleinere Laptops\ **XL / XXL:** Große Laptops, Desktop PCs und Wide-Screens * Wähle für jeden Viewport das passende Bild aus der Medienbibliothek des CMS oder füge ein neues Bild hinzu. * **Weitere Slides hinzufügen**: Klicke auf "+ Eintrag hinzufügen", um zusätzliche Slides zum Slider hinzuzufügen. ### Vorhandene Slides bearbeiten * **Zu den Slides navigieren**: Navigiere zu der Bearbeitungs-Seite und klappe dort die vorhandene Slider-Komponente auf. Wähle den Slide, der zu bearbeiten ist und klicke zum Aufklappen auf die Leiste mit dem Pfeil. * **Anzeigestatus festlegen**: Über "Anzeigestatus" mit der Auswahl "Ja" wird der Slide im Slider angezeigt. Mit der Auswahl "Nein" wird der Slide nicht angezeigt. So können Slides auch vorübergehend oder nur für eine bestimmte Zeit ausgeblendet- und später wieder einblendet werden. * **Beschreibung ändern**: Im Feld “Beschreibung” kannst per Klick in das Feld die Beschreibung des jeweiligen Slides geändert werden, die zur besseren Übersicht im CMS dient. * **Link hinzufügen**: Im Feld "Link" kann die Verlinkung bearbeiten werden. Beim Klick auf den "Slide" wird der Besucher zu dieser Verlinkung weitergeleitet. Hierfür stehen verschiedene "Linktypen" zur Verfügung: * **Product**: Gib eine Produktnummer ein, um den Besucher zur Produktdetailansicht dieses Produktes weiterzuleiten. * **Category**: Gib einen Kategorie-Index ein, um den Besucher zur Kategorieseite dieser Kategorie weiterzuleiten. * **Internal**: Gib spezifische Pfade oder Routen an, die zu anderen Seiten oder Ressourcen innerhalb deines Online-Shops führen. * **URL**: Gib eine URL an, um den Besucher zu dieser URL weiterzuleiten. * **Bilder anpassen**: Um die Bilder des Slides anzupassen, gibt es verschiedene Möglichkeiten. * Möchte man beispielsweise alle Bilder für jede Bildschirmbreite gleichzeitig entfernen, muss man auf das Mülleimer-Icon des Feldes “Bilder“ klicken. * Möchte man nur einzelne Bilder austauschen, entfernen oder das Bild bearbeiten, kann man die Icons, die sich direkt bei dem jeweiligen Bild befinden, benutzen. * Klicke auf das + Symbol um, das Bild mit einem anderen Bild aus der Medienbibliothek oder einem neu hochgeladenen Bild zu tauschen. * Die Option Link kopieren mit dem Link-Symbol kopiert den Bild-Pfad in die Zwischenablage. * Klicke auf das Mülleimer-Icon um, das Bild für die jeweilige Bildschirmbreite zu entfernen. * Über das Stift-Symbol kommst man zum Bearbeitungsmodus des Bildes, wo man den Dateinamen, den Alternativtext, den Bildtext und die Location des Bildes anpassen kann. ### Testmodus * **Testmodus**: Vor dem speichern muss über die Auswahl "JA / NEIN" festgelegt werden, ob die Änderungen im [Testmodus](/frontend/referenz/module/wstestmode) oder im Livemodus angezeigt werden sollen. *** ## Anpassen von Product-Slidern am Beispiel der Startseite ### Anpassen des Product-Slider “Unsere Topseller“ * **Zum Product-Slider navigieren**: Navigiere zu der Bearbeitungs-Seite und klappe dort die Product- Slider-Komponente “Unsere Topseller” auf. * **Überschrift**: Ändere die Überschrift per Klick in das Feld und trage eine neue ein. * **Kategorie-Index**: Bevor ein neuer Kategorie Index in das Feld geschrieben wird, muss der vorhandene erst gelöscht werden, da nicht zwei verschiedene ganze Kategorien in einem Slider abgebildet werden können. * **Volle Bildschirmbreite**: Mit der Option “Ja” wird festgelegt, dass der Slider über die ganze Bildschirmbreite geht - die Option “Nein” sorgt dafür, dass der Slider sich an der Breite der anderen Elemente anpasst. ### Anpassen des Product-Slider (manual) “Unsere beste Bekleidung“ * **Zum Product-Slider (manual) navigieren**: Navigiere zu der Bearbeitungs-Seite und klappe dort\ die Product-Slider (manual) Komponente “Unsere beste Bekleidung” auf. * **Überschrift**: Ändere die Überschrift per Klick in das Feld und trage eine neue ein. * **Produktliste**: Klicke in das Feld und füge einen neuen Produkt-Index hinzu oder entferne ein Produkt aus dem Slider durch das entfernen der Produktnummer.\ Achte dabei stets darauf, dass es nicht zu Dopplungen von Kommas kommt, oder zwischen zwei Produktnummern ein Komma vergessen wird, um fehlerhafte Anzeigen zu vermeiden. * **Volle Bildschirmbreite**: Mit der Option “Ja” wird festgelegt, dass der Slider über die ganze Bildschirmbreite geht und die Option “Nein” sorgt dafür, dass der Slider sich an der Breite der anderen Elemente anpasst. *** ## Anpassen von einem Product-Teaser am Beispiel der Startseite ### Anpassen des Product-Teasers “Technik-Neuheiten“ * **Zum Product-Teaser navigieren**: Navigiere zu der Bearbeitungs-Seite und klappe dort\ die Product-Teaser-Komponente “Technik-Neuheiten” auf. * **Überschrift**: Ändere die Überschrift per Klick in das Feld und trage eine neue ein. * **Produktliste**: Klicke in das Feld und füge einen neuen Produkt-Index hinzu oder entferne ein Produkt aus dem Teaser durch das entfernen der Produktnummer.\ Achte dabei stets darauf, dass es nicht zu Dopplungen von Kommas kommt, oder zwischen zwei Produktnummern ein Komma vergessen wird, um fehlerhafte Anzeigen zu vermeiden. *** ## Strapi für Subshops erweitern ### Neue Sprache anlegen * Einstellungen → Internationalisierung * “Neue Sprache hinzufügen” * Sprache auswählen. * Anzeigenamen **nicht** ändern. * Locale-ID notieren / kopieren. Bspw. “Französisch (**fr**) - **fr** wäre hier die Locale-ID. * Speichern.\\ ### Sprache einem Subshop zweisen * Content-Manager → Konfiguration * “+ Eintrag hinzufügen” wählen oder einen bestehenden bearbeiten. * Unter “WEBSALE Subshop ID” kann nun eine kommaseparierte Liste an Subshop-IDs eingetragen werden. * Unter “Strapi Locale ID” muss die im vorherigen Schritt kopierte “Locale-ID” eingefügt werden. * Im Anschluss speichern.\\ Der WEBSALE Strapi Connector beachtet nun automatisch die neue Sprache.\ Content, der im Content-Manager für diese Sprache gepflegt wird, wird auf dem Shopserver in die Verzeichnisse für Subshops abgelegt. Jeder Wert (kommasepariert) stellt einen Subshop-Ordner dar. # Komponenten & Sammlungen in strapi Source: https://dokumentation.websale.de/strapi-cms/komponenten-sammlungen-in-strapi Inhaltsstrukturen in strapi verstehen: Komponenten, Sammlungen und Einzel-Einträge im WEBSALE-Standard korrekt anlegen und sicher erweitern. Auf dieser Seite wird erklärt, wie Inhalte in Strapi strukturiert werden und welche Rolle Komponenten, Sammlungen und Einzel-Einträge dabei spielen. Sie erfahren, wofür die jeweiligen Content-Typen verwendet werden, wie sie sich unterschieden und wie sie im Content-Manager zur Pflege von Inhalten zusammenspielen. Ziel ist es, die in **WEBSALE** standardmäßig bereitgestellten Strukturen besser zu verstehen, Inhalte korrekt anzulegen und bestehende Inhaltsbereiche sicher zu erweitern - ohne, dass Strapi als Page-Builder verstanden wird. *** ## Komponenten Wie in vielen anderen Content-Management-Systemen dienen Komponenten als wiederverwendbare Elemente, die zur Gestaltung und Strukturierung des Onlineshops genutzt werden können. Diese Komponenten sind im Grunde vordefinierte Bausteine, die spezifische Funktionen oder Layouts implementieren und die in verschiedenen Teilen des Shops eingesetzt werden können. ### Übersicht der Standard-Komponenten Eine Übersicht aller im Standardumfang zur Verfügung stehenden Komponenten ist über das linke Seitenmenü unter dem Navigationspunkt "Content-Type Builder" einsehbar. Sofern der Navigationspunkt "Content-Type Builder" nicht sichtbar ist, besteht die Möglichkeit, dass die entsprechenden Berechtigungen in deinem Nutzerkonto fehlen. In diesem Fall muss sich an den entsprechenden Mitarbeiter im Unternehmen gewendet werden, der die entsprechenden Rollen zuweisen kann. 5cf732a0 C104 4a8d A3dd C21cddfbc8b7 #### Content Die "Content"-Komponente beinhaltet einen Editor, der in seiner Funktionalität einem Texteditor, wie er beispielsweise von Microsoft Word bekannt ist, ähnelt. In diesem können Texte, Medien, Tabellen sowie weitere Elemente eingefügt, bearbeitet oder formatiert werden. Zusätzlich besteht die Option, CSS-Klassen zuzuweisen, um das Aussehen weiter zu spezifizieren und zu bestimmen. Außerdem kann eingestellt werden, ob der Inhalt über die gesamte Bildschirmbreite angezeigt werden oder sich an bestehende Komponenten anpassen soll. #### WS Inquiry DIe "WS Inquiry"-Komponente dient der Anzeige eines Websale-Formulars auf der Seite. In der VX-Version von WEBSALE erfolgt die Einbindung der Formulare allerdings ausschließlich über das Admin-Interface. Eine Anleitung hierzu kann [hier](/konfiguration/inquiry-formulare) eingesehen werden. #### Slider Ein Slider ist eine interaktive Komponente in unserem Shop-System, die darauf ausgelegt ist, Inhalte dynamisch in einer horizontal scrollbaren Anzeige zu präsentieren. Diese Form der Darstellung ermöglicht es, mehrere Elemente wie Bilder, Produkte oder Werbebanner auf begrenztem Raum attraktiv und benutzerfreundlich zu zeigen. Nutzer können durch die Inhalte blättern, was eine aktive und engagierte Interaktion mit dem angebotenen Content fördert. Die verschiedenen Slider-Typen in unserem System - der allgemeine Bild-Slider, der Product-Slider und der Product-Slider für Produkte einer Kategorie - nutzen diese dynamische Präsentationsform, um jeweils spezifische Anwendungsfälle zu unterstützen, sei es durch das Anzeigen großer Banner für Marketingzwecke oder das detaillierte Highlighten ausgewählter Produkte. #### Slider Dies ist eine grundlegende Slider-Komponente, die hauptsächlich für große Banner und Bilder genutzt wird. Sie unterstützt das Konzept des „responsive Designs“, indem für verschiedene Viewports (Anzeigegrößen und -geräte) unterschiedliche Bilddateien hinterlegt werden können. Jeder Slide innerhalb dieses Sliders kann mit einer individuellen Verlinkung versehen werden, um Nutzer gezielt zu weiterführenden Informationen oder anderen Bereichen deines Shops zu führen. Wenn Texte auf den Slides gewünscht sind, müssen diese bereits auf den Bannern und Bildern enthalten sein. Text kann innerhalb der Standard-Komponente nicht über die Strapi-Eingabemaske hinzugefügt werden, was die Gestaltung der visuellen Inhalte vor dem Upload erfordert. #### Product-Slider (manual) Product Slider Manual Mit dieser Komponente kann ein Slider an Produktboxen im Shop angezeigt werden. Die Eigenschaften und Funktionen des Sliders werden direkt im Shop konfiguriert. Dies beinhaltet Einstellungen wie Breakpoints, die Schnelligkeit beim Wechsel der Slides, die Anzeige von Navigationspfeilen und weitere Verhaltensweisen des Sliders. Diese Angaben können nicht über das CMS angepasst werden. Änderungen an der [Konfiguration des Sliders](/strapi-cms/templates-fur-strapi-inhalte-anpassen) müssen immer über den Template-Manager vorgenommen werden. Der Zusatz „Manual“ bedeutet, dass die angezeigten Produkte selbst ausgewählt werden können. Dazu müssen die Produktnummern der gewünschten Produkte als komma-separierte Liste in das Feld „Produktliste“ eingetragen werden. Wenn gewünscht, kann dem Slider eine Überschrift hinzugefügt werden.. Dies hilft den Kunden zu verstehen, welche Produkte sie unter diesem Slider finden können. Außerdem besteht die Möglichkeit zu bestimmen, ob der Slider über die gesamte Bildschirmbreite angezeigt werden soll oder nicht. Zu beachten ist, dass die eingegebenen Produktnummern nicht automatisch auf Richtigkeit überprüft werden. Wenn also in der Storefront keine Anzeige des gewünschten Produktes erfolgt, dann überprüfe bitte die entsprechenden Eingaben. #### Product-Slider für Produkte einer Kategorie Product Slider Produkte Diese Komponente funktioniert ähnlich wie die „Product Slider (manual)“-Komponente. Der Unterschied besteht darin, dass hier keine komma-separierte Liste von Produktnummern verwendet wird. Stattdessen wird hier ein Kategorie-Index eingetragen, aus dem die Produkte automatisch geladen und im Slider angezeigt werden. Es ist nicht möglich, einzelne Produkte der Kategorie von der Anzeige im Slider auszuschließen. Die Produkte werden in der Reihenfolge dargestellt, wie sie in der Shop-Datenbank hinterlegt sind. Eine spezielle Sortierangabe oder Sortierreihenfolge ist nicht möglich. Änderungen an Produkten innerhalb dieser Kategorie spiegeln sich automatisch im Slider wider, sodass bei Produktaktualisierungen keine manuellen Anpassungen am Slider notwendig sind. Dies sorgt für eine stets aktuelle und wartungsarme Präsentation der Produkte. Es ist zu beachten, dass der eingegebene Kategorie-Index nicht auf Richtigkeit überprüft wird. Wenn also in der Storefront keine Anzeige der gewünschten Kategorie erfolgt, dann muss die Eingabe des Kategorie-Indexes nochmals überprüft werden. #### Product-Teaser Product Teaser Ein Product-Teaser ist eine visuell ansprechende Komponente in unserem Shop-System, die dazu dient, einzelne Produkte oder eine kleine, ausgewählte Gruppe von Produkten prominent und auffällig darzustellen. Im Gegensatz zu einem Product-Slider, der viele Produkte in einer dynamischen, scrollbaren Anzeige präsentiert, konzentriert sich der Product-Teaser auf die Hervorhebung bestimmter Produkte. Bei der Anlage mehrerer Teaser werden diese nicht gescrollt, sondern je nach Definition der Storefront nebeneinander oder untereinander angezeigt, was eine flexible und anpassbare Darstellung ermöglicht. Die Produkte für den Product-Teaser können selbst gewählt werden, in dem die gewünschten Produktnummern in das Feld „Produktliste“ als komma-separierte Liste eingetragen werden. Bitte beachte, dass die eingegebenen Produktnummern nicht automatisch auf Richtigkeit überprüft werden. Wenn also in der Storefront keine Anzeige des gewünschten Produktes erfolgt, dann muss die Eingabe der Produktnummern nochmals überprüft werden. Zusätzlich kann, wenn gewünscht, eine Überschrift für den Teaser hinzugefügt werden, um dem Kunden zu verdeutlichen, welche Produkte er unter dem Teaser-Bereich findet. #### Link Helper Eine der Standard-Komponenten in Strapi ist darauf ausgelegt, das Hinzufügen von Verlinkungen zu erleichtern. Hierfür stehen vier Linktypen zur Verfügung, die flexibel genutzt werden können, um unterschiedliche Arten von Links zu erstellen: * **Product**: * Im Feld "Link" muss die Produktnummer angegeben werden - Strapi generiert daraufhin automatisch einen Link, der direkt zur Detailseite dieses Produkts führt. * **Category**: * Im Feld “Link” muss ein Kategorie-Index eingetragen werden.. Der Link führt den Nutzer dann direkt zur entsprechenden Kategorieseite, wo alle Produkte dieser Kategorie aufgelistet sind. * **Internal**: * Für interne Verlinkungen innerhalb des Onlineshops können spezifische Pfade oder Routen angeben werden, die zu anderen Seiten oder Ressourcen innerhalb des Online-Shops führen. * **External**: * Dieser Linktyp ermöglicht es, eine externe URL einzugeben. Diese Option wird genutzt, um Besucher auf andere Websites zu leiten, die nicht zum eigenen Shop gehören. #### Meta-Information Meta-Informationen sind entscheidend für die Suchmaschinenoptimierung (SEO) des Online-Shops. In Strapi können diese Informationen gezielt für jede Seite festgelegt werden, um die Sichtbarkeit und Auffindbarkeit in Suchmaschinen zu verbessern. * **Meta Titel** * Der Meta-Titel ist ein kritischer SEO-Faktor und erscheint im Browser als Tab-Name sowie in den Suchergebnissen als Überschrift des Eintrags. * Gib den Titel der Seite ein, der präzise das Thema oder den Inhalt der Seite widerspiegelt. * **Meta Beschreibung** * Die Meta-Beschreibung bietet eine kurze und prägnante Zusammenfassung des Seiteninhalts. Diese Beschreibung erscheint unter dem Titel in den Suchergebnislisten, z.B. von Google und kann die Klickrate beeinflussen. * Formuliere eine ansprechende Beschreibung, die den Inhalt der Seite effektiv zusammenfasst und zum Klicken einlädt. * **SEO-URL** * Die SEO-URL ist die Adresse, unter der die Seite aufrufbar sein wird. Sie sollte sprechend und SEO-freundlich sein. * Standardmäßig wird die URL mit cms/ beginnen. Für spezielle Anforderungen oder zusätzliche Verzeichnisse steht Ihr WEBSALE Ansprechpartner zur Verfügung. Die Systemadministration wird notwendige Anpassungen vornehmen und die Verzeichnisse entsprechend einrichten. * **Meta Robots** * Das Meta Robots Tag steuert das Crawling- und Indexierungsverhalten der Suchmaschinen für die Seite. * Es kann zwischen verschiedenen Anweisungen wie index, follow, noindex, follow, index, nofollow und noindex, nofollow gewählt werden, um zu steuern, ob und wie Suchmaschinen die Seite indexieren und verlinken. * Für eine detaillierte Erklärung der verschiedenen Meta Robots Tags empfehlen wir, den Google-Leitfaden zur Steuerung des Crawlings und der Indexierung zu konsultieren: [https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag?hl=de](https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag?hl=de) #### Responsive Image Die "Responsive Image"-Komponente ermöglicht es, Bilder so anzulegen, dass sie optimal auf verschiedenen Bildschirmgrößen dargestellt werden. Diese Komponente unterstützt die Definition von Bildern für verschiedene responsive Breakpoints, wodurch sichergestellt wird, dass der Shop auf allen Geräten gut aussieht. Responsive Breakpoints sind spezifische Bildschirmbreiten, bei denen das Layout der Website sich ändert, um eine bessere Benutzererfahrung zu bieten. Diese sind in vielen CSS-Frameworks wie Bootstrap definiert. Für eine detaillierte Erklärung der Breakpoints im Framework "Bootstrap" besuche [Bootstrap Breakpoints](https://getbootstrap.com/docs/5.3/layout/breakpoints/#available-breakpoints). Weise jedem Breakpoint eine passende Bilddatei zu. Typische Breakpoints umfassen Größen für XS (extra small), SM (small), MD (medium), LG (large) und XL (extra large). Das Bild, das im Feld XS eingetragen wird, dient als "Fallback". Sollte für einen größeren Breakpoint keine spezifische Bilddatei hinterlegt sein, wird automatisch das Bild aus dem XS-Feld angezeigt. #### WS Subshop Locale Der Baustein „WS Subshop Locale“ ist speziell dafür entwickelt, um eine Verbindung zwischen den in Strapi hinterlegten Sprachlokalisationen (Locales) und den damit korrespondierenden WEBSALE Subshops herzustellen. Dies ermöglicht eine gezielte Steuerung von sprachspezifischen Inhalten für verschiedene Subshops. * **wsSubshopId**: * In diesem Feld wird die ID der Subshops eingetragen, die der jeweiligen Sprachvariante zugeordnet sind. Dies dient der Zuordnung von sprachspezifischen Inhalten zu den entsprechenden Subshops. * **strapiLocaleId**: * Hier wird die spezifische Locale-ID eingetragen, die in Strapi verwendet wird, um die Sprache zu definieren. Dies ist besonders wichtig, um sicherzustellen, dass der richtige sprachliche Inhalt den entsprechenden Subshops zugeordnet wird. So kann beispielsweise der Eintrag für die Sprachevariante / Locale “Deutsch (de)” folgendermaßen aussehen: | wsSubshopId | strapiLocaleId | | ------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- | | Deutsch, Österreich, subshop-ch | de | | **Anmerkung:**
    Hier kann eine kommaseparierte Liste an mit der Locale in
    Verbindung stehenden Subshops eingetragen werden. | **Anmerkung:**
    Hier soll nur die ID der Locale eingetragen werden.
    Bspw. "de" - nicht "Deutsch (de)". | *** ## Erstellen neuer Komponenten In Strapi selbst können neue Komponenten erstellt und deren Aufbau festgelegt werden.\ Damit diese Komponenten später im Shop dargestellt werden, muss ein Template-Manager bzw. Designer immer Anpassungen an den Shop-Templates vornehmen. Beispiel Stellenanzeige Das Beispiel beschreibt das Erstellen einer Komponente namens “Stellenanzeige”. Diese Komponente soll später folgende Inhalte in der Storefront anzeigen: * Titel (Datenfeld des Datentyps: Text) * Anforderungen (Datenfeld des Datentyps: Text) * Taetigkeitsbeschreibung (Datenfeld des Datentyps: Text) * Wir\_Bieten (Datenfeld des Datentyps: Text) * Schlussformel (Datenfeld des Datentyps: Text) * Gehalt (Datenfeld des Datentyps: Zahl) * Datum (Datenfeld des Datentypes: Datum) * Adresse (Datenfeld des Datentyps: Text) * Mail\_Ansprechpartner (Datenfeld des Datentyps: E-Mail)\\ ### Komponente im Content-Type Builder erstellen * Öffne im Strapi Admin Dashboard den **Content-Type Builder** im linken Seitenmenü * Wähle im Untermenüpunkt **Komponenten** die Option **+ Neue Komponente erstellen** * Vergib einen Anzeigenamen, wähle oder erstelle eine Kategorie und vergib ein Symbol für die Komponente, falls gewünscht * Klicke auf **Weiter** Strapi Konfiguration ### Aufbau der Komponente definieren und Felder erstellen Komponente Definieren Strapi * Für jedes Detail (Titel, Anforderungen, Datum, Gehalt) kannst entschieden werden, ob ein separates Datenfeld (z. B. Text, Datum, Zahl) oder eine Textarea benötigt wird, in der alle Informationen gleichzeitig eingegeben werden können * Erstelle das erste Feld für die Komponente und wähle bei der Erstellung einen Datentyp, z.B. Datentyp "Text" für das Feld "Titel" * Ein Datentyp in Strapi definiert die Art der Daten, die ein Feld aufnehmen kann. Beispiele sind "Text" für Textzeilen, "Datum" für Datumsangaben und "Zahl" für numerische Werte. Jeder Datentyp bestimmt, wie die Daten im System verarbeitet und angezeigt werden. * Mehr Informationen zu den “Datentypen” befinden sich in der [strapi Dokumentation](https://docs.strapi.io/user-docs/content-type-builder/configuring-fields-content-type). * Vergib dann einen Namen für dieses Feld und konfiguriere zusätzliche Optionen, die je nach Datentyp verfügbar sind. * Speichere das Feld mit "Fertig" oder erstelle direkt im Dialogfenster weitere Felder. Fahre so fort, bis alle benötigten Felder für die "Stellenanzeige" angelegt sind. ### Komponente in Inhaltsseiten integrieren * Wähle im Menüunterpunkt "Sammlungen" die "Inhaltsseiten" * Wähle eine Inhaltsseite aus, die zukünftig die Komponente “Stellenanzeige” beinhalten soll * Drücke innerhalb des Feldes "Content" auf “Komponente hinzufügen” und wähle “Bereits existierende Komponente nutzen” * Wähle im Dropdown-Menü die neue Komponente "Stellenanzeige". * Drücke auf “Fertig” und speichere die Änderungen. * Wiederhole den Vorgang für jede Seite, auf der die Komponente "Stellenanzeige" verwendet werden soll. Inhaltsseiten Strapi Unter "Content" → "Komponente hinzufügen" öffnet sich das Auswahlfenster für das hinzufügen der neuen Komponente. Komponente Dyn Zone Strapi In der Auswahlliste muss die neue Komponente ausgewählt werden. ### Shop-Template und Design Anpassungen * Informiere den Template-Manager deines Onlineshops über die neu erstellte Komponente "Stellenanzeige". * Besprecht gemeinsam, wie die neue Komponente aufgebaut sein soll und wie sie visuell gestaltet werden soll, damit sie in das bestehende Design des Onlineshops passt. * Der Designer passt die Templates entsprechend an, um die Daten aus der neuen Komponente richtig darzustellen. ### 1.2.5. Überprüfung und Freigabe * Nachdem die Komponente erstellt, zugewiesen und die Templates angepasst wurden, kann die Änderungen auf der bearbeiteten Seite angesehen werden. Stelle sicher, dass alles wie erwartet funktioniert und visuell ansprechend ist. ### 1.2.6. Wichtiger Hinweis beim Erstellen von Komponenten * Komponenten sollten gründlich geplant und ausgeklügelt sein, bevor sie produktiv genutzt werden. Abstimmungen, mit dem Template-Manager oder Designer und ausführliche Überlegungen zum Aufbau sind entscheidend, um eine Komponente richtig zu gestalten und zukünftige Anpassungen zu minimieren. Weitere Informationen für Template-Manager befinden sich [hier](/strapi-cms/templates-fur-strapi-inhalte-anpassen). * Sei dir bewusst, dass das Bearbeiten oder Löschen von Komponenten in laufenden Projekten zu unerwarteten Verhaltensweisen oder Fehlern führen kann. *** ## Komponenten bearbeiten ### Bestehende Komponente bearbeiten * Wähle im linken Menü „Content-Type Builder“. Dieser Bereich ermöglicht es, die Strukturen der Daten in Strapi zu definieren und anzupassen. * Unter dem Menüpunkt „Komponenten“ ist eine Liste aller angelegten Komponenten dargestellt. Wähle die Komponente aus, die bearbeitet werden soll. * Um sie im Admin-Panel leichter identifizierbar zu machen, können der Anzeigename und das Icon der Komponente bearbeitet werden. * Es ist möglich, Felder zu einer bestehenden Komponente hinzuzufügen, zu bearbeiten oder zu entfernen. Diese Flexibilität erlaubt es, Komponenten entsprechend neuen Anforderungen anzupassen. * Damit die Änderungen an den Komponenten später im Shop dargestellt werden, sollte ein Template-Manager bzw. Designer immer die Shop-Templates überprüfen. Gegebenenfalls sind Änderungen erforderlich. Weitere Informationen für Template-Manager befinden sich [hier](/strapi-cms/templates-fur-strapi-inhalte-anpassen). ### Hinweise & Tipps beim Bearbeiten von Komponenten * Obwohl Strapi im "Develop" Modus ausgeliefert wird, der das Anlegen und Bearbeiten von Komponenten zulässt, sollte das ständige Anpassen bestehender Komponenten, die bereits in der Produktion genutzt werden, vermieden werden. Strapi ist prinzipiell nicht dafür ausgelegt, dass Komponenten, die schon mit Daten befüllt und in Gebrauch sind, fortlaufend geändert werden. * Wichtig zu erwähnen ist, dass das Bearbeiten oder Löschen von Komponenten in laufenden Projekten zu unerwarteten Verhaltensweisen oder Fehlern führen kann. Insbesondere das Löschen von Komponenten kann schwerwiegende Auswirkungen haben, wenn diese bereits häufig genutzt werden. *** ## Arbeiten mit Komponenten ### Beschreibung für Komponenten Zur Optimierung der Übersichtlichkeit über die Komponenten der Seite besteht an dieser Stelle die Möglichkeit, eine Beschreibung in das Feld "Beschreibung" einzugeben. ### Design der Komponenten #### Ergänzende CSS-Klassen für Komponenten Jede Komponente in Strapi bietet die Möglichkeit, spezifische CSS-Klassen zuzuweisen. Diese Klassen ermöglichen es, das Aussehen der Komponenten anzupassen und visuell in das Gesamtdesign des Shops zu integrieren. Die zugewiesenen CSS-Klassen müssen in den CSS-Dateien deines Shops hinterlegt sein. Detaillierte Anleitungen zum Erstellen und Verwalten dieser CSS-Dateien befinden sich in der WEBSALE Dokumentation. Dort wird beschrieben, wie und wo CSS-Dateien für den Shop hinterlegt werden können, um eine nahtlose Integration und ein kohärentes Design zu gewährleisten. #### Grundlegendes Design der Komponenten Während innerhalb von Strapi-Komponenten stilistische Anpassungen mittels CSS-Klassen vorgenommen werden können, wird das grundlegende Design der Inhalte hauptsächlich über die Shop-Templates definiert. Wenn grundsätzliche Änderungen am Design der durch Strapi bereitgestellten Inhalte gewünscht sind, sollten diese Änderungen direkt an den Shop-Templates vorgenommen werden, auf denen die Strapi-Inhalte platziert werden. Dies umfasst Änderungen an Layouts, Farbschemata, Schriftarten und anderen Designelementen, die das Erscheinungsbild des Online-Shops prägen. Für detaillierte Informationen darüber, wie und wo diese Shop-Templates bearbeitet werden können, verweisen wir erneut auf die WEBSALE Dokumentation. Dort finden sich ausführliche Anleitungen und Hilfestellungen, die durch den Prozess der Template-Anpassung führen und sicherstellen, dass Designänderungen effektiv und konsistent umgesetzt werden. ### Effektive Kombination von Komponenten und Sammlungen Die Verwaltung von Inhalten in Strapi kann effizienter gestaltet werden, indem Komponenten und Sammlungen kombiniert werden. Dieses Vorgehen minimiert den Pflegeaufwand und sorgt für Konsistenz über verschiedene Seiten hinweg. #### Komponenten und ihre direkte Nutzung Zunächst wird eine Komponente "Stellenanzeige" im Content-Type Builder erstellt. Diese Komponente enthält Felder wie Bezeichnung, Beginn und Gehalt. Die Komponente kann direkt auf einer spezifischen Inhaltsseite, wie z.B. einer Karriere-Seite, verwendet werden. Dort werden die spezifischen Daten der Stellenanzeigen manuell eingetragen. Wenn dieselbe Komponente "Stellenanzeige" auch auf einer anderen Seite, wie "Über uns", genutzt werden soll, müssen die gleichen Daten erneut manuell eingefügt werden. Dies führt zu einem doppelten Pflegeaufwand und erhöht das Risiko von Inkonsistenzen. #### Komponenten in Sammlungen nutzen Um das Problem des doppelten Pflegeaufwands von Komponenten mit gleichem Inhalt, z.B. Stellenanzeigen, zu lösen, wird zusätzlich eine Sammlung "Stellenanzeigen" erstellt, in der alle aktuellen Stellenanzeigen zentral verwaltet werden. Jede Stellenanzeige wird als ein Eintrag in dieser Sammlung angelegt. Die Sammlung "Stellenanzeigen" kann dann als Ganzes auf verschiedenen Seiten wie "Karriere" und "Über uns" eingebunden werden. Änderungen an einer Stellenanzeige innerhalb der Sammlung wirken sich automatisch auf alle Seiten aus, auf denen die Sammlung eingebunden ist. Dies gewährleistet, dass die Informationen auf allen Seiten konsistent und aktuell sind, ohne dass jede Seite einzeln angepasst werden muss. Es reduziert den Pflegeaufwand und minimiert Fehlerquellen. ## Transfer von Komponenten zwischen WEBSALE Strapi Instanzen Strapi ermöglicht es, fertige Komponenten zwischen verschiedenen Instanzen, die von WEBSALE installiert worden sind, zu transferieren. Dieser Prozess erleichtert die Wiederverwendung von entwickelten Komponenten und sorgt für Effizienz und Konsistenz über verschiedene Projekte hinweg.   * **Zugriff auf die empfangende Instanz**: Öffne auf der empfangenden Instanz den Pfad \/api/component-creator. Diese URL führt direkt zum API-Endpunkt, der für den Transfer von Komponenten zuständig ist. Folge den Anweisungen im Feld “Authenticate”. Gebe hierfür die Common-ID ein, mit welcher die URL der WEBSALE Strapi Instanz gebildet wird. * **Authentifizierung**: Authentifiziere dich mit den API-Zugangsdaten. Dies bestätigt deine Berechtigung, Änderungen vorzunehmen und auf die Liste der Komponenten zuzugreifen. Die API-Zugangsdaten, die für den Transfer benötigt werden, entsprechen den initialen Zugangsdaten der Strapi Instanz. * **Auswahl der Komponente**: Die empfangende Instanz zeigt eine Liste der verfügbaren Komponenten. Wähle die Komponente aus, die transferiert werden sollen. Eine Vorschau des Schemas dieser Komponente wird zur Überprüfung angezeigt. * **Transfer der Komponente**: Wähle unter „Transfer“ die zugehörige Komponentengruppe aus, in der die Komponente gespeichert werden soll, oder erstelle eine neue Gruppe für bessere Organisation im Dashboard. Drücke auf „Transfer“, um die Komponente zur empfangenden Instanz zu senden. * **Automatische Erstellung und Speicherung**: Das Schema der ausgewählten Komponente wird automatisch an einen neuen API-Endpunkt der empfangenden Instanz gesendet. Dort wird eine identische Komponente mit demselben Schema automatisch angelegt und gespeichert. * **Neustart der Anwendung**: Aufgrund der Änderungen in den src/ Dateien wird die Strapi Instanz automatisch im Hintergrund neu gestartet. Die Instanz ist nach dem Neustart innerhalb weniger Sekunden wieder erreichbar. * **Überprüfung**: Nach dem Neustart steht die neue Komponente im Dashboard der empfangenden Instanz zur Verfügung. Überprüfe, ob die Komponente korrekt angelegt wurde und funktionsfähig ist.   *** ## Sammlungen & Einzel-Einträge ### Neue Sammlung oder neuen Einzel-Eintrag erstellen Um unterhalb der Bereiche **Sammlungen** oder **Einzel-Einträge** neue Punkte zu erstellen, muss ein neuer **Content-Typ** erstellt werden. ### Neue Sammlung oder neuen Einzel-Eintrag erstellen * Im **Content-Type Builder** kann man Content-Typen anlegen, ihre Felder definieren und Schemata festlegen, die bestimmen, welche Art von Daten gehalten und wie diese strukturiert werden. * Es kann gewählt werden, ob man einen Content-Typ unter **Sammlungen** (Collection Types) oder **Einzel-Einträgen** (Single Types) erstellen möchtest. Dafür stehen die Buttons “+ Neue Sammlung erstellen” oder “+ Neuen Einzel-Eintrag erstellen” zur Verfügung. * Gib dem Content-Typ einen aussagekräftigen Namen und definiere englische API-Endpunkte. Zum Beispiel könnte für den Content-Typ "Stellenanzeigen" der singulare API-Endpunkt “job-ad” und der plurale API-Endpunkt “job-ads” gewählt werden. Inhaltstyp Erstellen Strapi * Nachdem alle Einstellungen vorgenommen wurden, speichere diese. * Neue Content-Typen werden automatisch übertragen. Damit das json-File erzeugt wird, müssen für diese neuen Content-Typen vor der ersten Übertragung entsprechende Berechtigungen gesetzt werden.\ Dies funktioniert wie folgt: * Navigiere zu Einstellungen > NUTZER- & BERECHTIGUNGEN-PLUGIN > Rollen > Authenticated * Nun erscheint eine Liste der erstellten Content-Typen. Klappe per Klick deinen neu erstellten \ Content-Typ auf. * Hier klickt man nun auf die Checkbox “Alles auswählen“ damit dem Content-Typ alle nötigen Rechte gewährt werden. * Bestätige deine Änderungen über “Speichern”. Strapi Erstellen * Die Namensgebung für die JSON-Dateien erfolgt hier über zwei Wege. * Ist im Content-Typ ein Feld mit dem Namen “TemplateName” enthalten, so lautet der Name der JSON-Datei so wie der Wert der in diesem Feld gespeichert wird. * Ist kein Feld mit diesem Namen enthalten, so lautet der Name der JSON-Datei bei\ Sammlungen: *\\_\.json*\ Einzel-Einträgen: *\.json* ### Nutzung im Content-Manager am Beispiel "Sammlungen" Im **Content-Manager** erfolgt die Verwaltung und Bearbeitung der Inhalte der neu angelegten Sammlung und/oder Einzel-Einträge basierend auf den vordefinierten Content-Typen. Es besteht die Möglichkeit, Inhalte entsprechend der festgelegten Regeln hinzuzufügen, zu bearbeiten oder zu löschen. * Wähle im Content-Manager die neu hinzugefügte Sammlung aus. * Wähle „Komponente“ und dann „Bereits existierende Komponente nutzen“. * Im Dropdown-Menü „Komponente auswählen“, wähle die gewünschte Komponente aus, z.B. „Kontakt“. * Bestimme, ob die Komponente wiederholbar sein soll, um dynamische Inhalte wie mehrere Ansprechpartner zu ermöglichen. * Im Content-Manager können über „+ Neuer Eintrag“ weitere hinzugefügt werden. * Fülle die Felder aus und speichere den neuen Eintrag. * Informiere den Template-Manager, um festzulegen, wie und wo die neuen Sammlungsdaten auf der Website angezeigt werden sollen. # Migration der strapi-Datenstruktur (Version 5) Source: https://dokumentation.websale.de/strapi-cms/migration-der-strapi-datenstruktur-v5 Anleitung zur Migration bestehender Shops auf die neue strapi Datenstruktur: neues JSON-Ausgabeformat, Unterschiede zur alten Struktur und Anpassung der Shop-Templates. Auf dieser Seite wird beschrieben, wie bestehende Shops auf die neue strapi-Datenstruktur migriert werden. Durch die Umstellung vom bisherigen Content-Sync auf die neue Sync-Middleware ändert sich das Format der JSON-Dateien, die strapi an den Shop übergibt. Shop-Templates, die auf der alten Datenstruktur basieren, müssen dafür angepasst werden. Die neue Sync-Middleware befindet sich derzeit in der Entwicklung. Auf dieser Seite wird die bereits bestätigte Datenstruktur beschrieben. ## Gilt die neue Datenstruktur schon für meinen Shop? Die neue Sync-Middleware wird mit dem Update auf strapi Version 5 eingeführt und ist ab dann der Standard. Vorher gibt es sie nicht. Daraus ergeben sich drei Fälle: | **Ihr Shop** | **Handlungsbedarf** | | ---------------------------------------------------- | -------------------------------------------------------------------- | | Nutzt strapi noch nicht | Keiner. | | Wird neu mit strapi Version 5 eingerichtet | Keiner. Der Shop erhält die neue Datenstruktur von Anfang an. | | Nutzt strapi bereits mit dem bisherigen Content-Sync | Einmalige Migration der Templates, wie auf dieser Seite beschrieben. | ## Was diese Seite behandelt und was nicht Diese Seite behandelt das neue Ausgabeformat der JSON-Dateien, die Unterschiede zur alten Struktur und die dafür nötigen Template-Anpassungen. **Nicht behandelt wird:** * **Das Anlegen oder Erweitern von Inhalten in strapi.** Das ist unabhängig von der Migration. Grundlagen dazu stehen unter [Grundlagen & Architektur von strapi](/strapi-cms/grundlagen-architektur-von-strapi). * **Die Darstellung neuer Inhaltsbausteine.** Ein Template stellt immer nur die Eingabemasken, Felder und Komponenten dar, die darin umgesetzt sind. Legt ein Redakteur eine neue Eingabemaske oder eine neue Komponente an, muss das Template dafür erweitert werden. Sowohl vor wie auch nach der Migration. Das Vorgehen steht unter [Templates für strapi Inhalte anpassen](/strapi-cms/templates-fur-strapi-inhalte-anpassen). ## Struktur dieser Anleitung Die Anleitung besteht aus zwei Teilen. Teil A erklärt die Grundlagen, Teil B ist die eigentliche Arbeitsanleitung. **Teil A – Grundlagen (Nachschlageteil):** * [Begriffe: strapi in fünf Sätzen](#begriffe-strapi-in-funf-satzen) * [Warum sich das Datenformat ändert](#warum-sich-das-datenformat-andert) * [Die zwei neuen Formate im Vergleich](#die-zwei-neuen-formate-im-vergleich) * [Das mapping-Format im Detail](#das-mapping-format-im-detail) und [Das schema-Format im Detail](#das-schema-format-im-detail) * [Änderungen gegenüber der alten Struktur](#anderungen-gegenuber-der-alten-struktur) **Teil B – [Templates migrieren: die acht Schritte](#templates-migrieren-die-acht-schritte):** | **Schritt** | **Was passiert** | **Wann nötig** | | ----------- | --------------------------------------- | ----------------------------------------------------- | | 1 | Betroffene Stellen im Template finden | Immer | | 2 | Testmodus-Weiche einbauen (Absicherung) | Immer, **vor** der ersten Änderung | | 3 | Dateinamen in den Ladeaufrufen anpassen | Immer | | 4 | Feldzugriffe umstellen | Immer | | 5 | Inhaltsblöcke (Dynamic Zone) anpassen | Wenn das Template Inhaltsblöcke rendert | | 6 | Medienzugriffe anpassen | Wenn Bilder oder Dateien aus strapi ausgegeben werden | | 7 | SEO-Felder aus `meta` lesen | Wenn das Template SEO-Angaben aus strapi ausgibt | | 8 | Im Testmodus prüfen und live schalten | Immer, als letzter Schritt | ## Begriffe: strapi in fünf Sätzen Diese fünf Begriffe werden auf der gesamten Seite verwendet und sind für die Verständlichkeit der Anleitung wichtig. | **Begriff** | **Bedeutung** | | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Eingabemaske** (in strapi: Content-Typ) | Die Vorlage, die festlegt, welche Eingabefelder ein Inhalt hat. Beispiel: eine Inhaltsseite mit den Feldern „Titel" und „Inhalt". | | **Eingabefeld** (Feld) | Ein einzelnes Feld dieser Maske. Jedes Feld hat einen technischen Feldnamen (beispielsweise `title`) und einen Feldtyp (Text, Bild, Ja/Nein …). | | **Dokument** | Ein konkret ausgefüllter Inhalt, beispielsweise die Seite „AGB". Pro Dokument und Sprache entsteht ein eigener Satz JSON-Dateien für den Shop (siehe [Die zwei neuen Formate im Vergleich](#die-zwei-neuen-formate-im-vergleich)). | | **Komponente** | Ein wiederverwendbarer Baustein aus mehreren Feldern, beispielsweise ein Button aus „Label" und „Link". | | **Inhaltsblöcke** (in strapi: Dynamic Zone) | Ein Feld, in das der Redakteur beliebig viele Komponenten in beliebiger Reihenfolge einsetzt. Der typische Seitenaufbau einer Inhaltsseite. | Im Folgenden bedeutet Feldzugriff: die Stelle im Template, die den Wert eines Eingabefeldes aus der geladenen JSON-Datei ausliest, beispielsweise den Seitentitel. Ausführlicher sind diese Begriffe unter [Grundlagen & Architektur von strapi](/strapi-cms/grundlagen-architektur-von-strapi) beschrieben. ## Warum sich das Datenformat ändert Die Shop-Templates lesen Inhalte über die technischen Feldnamen aus den JSON-Dateien. Bisher war das Format dieser Dateien eng an die interne REST-Struktur von strapi gekoppelt. Bei jedem großen strapi-Versionssprung (zuletzt Version 4 auf 5) konnte sich diese Struktur ändern, was Anpassungen an Shop und Templates erforderlich machte. Die neue Sync-Middleware entkoppelt das Ausgabeformat von der strapi-internen Struktur. WEBSALE gibt damit eine eigene, feste Datenstruktur vor, die auch nach künftigen strapi-Updates stabil bleibt. Bestehende Shops müssen einmalig auf diese neue Struktur migriert werden. Danach sind sie updatefähig, ohne dass die Templates bei jedem strapi-Update angepasst werden müssen. Ein zweiter Grund liegt in strapi selbst: Über den [Content-Type Builder](/strapi-cms/grundlagen-architektur-von-strapi) können berechtigte Benutzer nicht nur Inhalte pflegen, sondern auch die Eingabemasken verändern. Felder können angelegt, umbenannt oder gelöscht werden. ## Die zwei neuen Formate im Vergleich Die neue Sync-Middleware schreibt jedes Dokument in zwei Dateien, in zwei unterschiedlichen Formaten. Beide enthalten dieselben Inhalte, nur anders angeordnet. Standardmäßig werden beide parallel erzeugt, damit ein schrittweiser Umstieg möglich ist. Dasselbe Dokument („AGB", Felder `title` und `content`) sieht in den beiden Formaten so aus: **mapping-Format** – jedes Eingabefeld ist direkt ein JSON-Key: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "title": "AGB", "content": [ … ] } ``` **schema-Format** – jedes Eingabefeld ist ein Eintrag in einer Liste, immer mit denselben drei Schlüsseln: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "contentType": "api::contentpage.contentpage", "meta": { … }, "fields": [ { "name": "title", "type": "string", "value": "AGB" }, { "name": "content", "type": "dynamiczone", "value": [ … ] } ] } ``` Übersicht der Unterscheidungen: | | **mapping-Format** | **schema-Format** | | -------------------------------------- | ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | | Dateiname | `.json` | `.schema.json` | | Template-Zugriff | direkt über den Feldnamen (`$cCMSData.title`) | über die Liste `fields`, einmalig in ein Name/Wert-Objekt überführt | | Aufwand der Migration | gering – im Wesentlichen entfällt der `attributes`-Wrapper | höher – die Feldzugriffe werden umgebaut | | Wenn ein Feld in strapi umbenannt wird | Der **Aufbau der Datei ändert sich**: der JSON-Key heißt anders. Das Template muss angepasst werden. | Der **Aufbau der Datei bleibt gleich**, nur der Wert von `name` ändert sich. Das Template muss ebenfalls angepasst werden. | | Wenn ein Feld hinzukommt oder wegfällt | Ein Key kommt hinzu oder fehlt. | Ein Listeneintrag kommt hinzu oder fehlt. | | Vorteil | einfachster Umstieg, kürzeste Templates | stabiler Dateiaufbau, Fehler sind leichter zu finden, Feldtyp ist mitgeliefert | Wichtig: **In beiden Formaten muss die Template-Stelle angepasst werden, wenn ein Eingabefeld umbenannt wird.** Kein Format schützt davor. Der Unterschied liegt nur darin, ob sich dabei der Aufbau der Datei ändert (mapping) oder nur ein Wert darin (schema). ## Das mapping-Format im Detail ### Aufbau Eine Inhaltsseite mit den Eingabefeldern „title" und „content" sieht so aus: ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "title": "AGB", "content": [ { "component": "elemente.ws-markup", "Markup": "AGB Content", "FullWidth": false } ], "_sync": { "contentType": "api::contentpage.contentpage" } } ``` * Jedes Eingabefeld ist ein JSON-Key auf oberster Ebene. Der Wert steht direkt darunter. * Der Schlüssel `_sync` ist kein Inhaltsfeld, sondern eine technische Ergänzung der Sync-Middleware. `_sync.contentType` nennt die Eingabemaske, aus der das Dokument stammt. * Inhaltsblöcke stehen als Array unter ihrem Feldnamen (hier `content`). Jeder Block trägt seinen Komponenten-Namen in `component` – **nicht** mehr in `__component` wie in der alten Struktur – und seine Felder direkt daneben. * Medien liegen als flaches, normalisiertes Medien-Objekt vor, identisch zum schema-Format (siehe [Medien](#medien-im-schema-format)). Der `data`/`attributes`-Wrapper der alten Struktur entfällt. Der Aufbau entspricht damit weitgehend der bisherigen Struktur, jedoch ohne den `attributes`-Wrapper und mit den weiteren Änderungen aus der [Gegenüberstellung unten](#anderungen-gegenuber-der-alten-struktur). ### Was Sie beim mapping-Format beachten müssen * **Feldnamen kommen ungefiltert durch.** Wird ein Eingabefeld in strapi umbenannt, ändert sich der JSON-Key. Die betroffene Template-Stelle muss dann angepasst werden. Das entspricht dem Verhalten, das Sie von benutzerdefinierten Produktdatenfeldern im Shop kennen. * **Kein Feldtyp in der Datei.** Anders als im schema-Format steht nicht dabei, ob ein Wert ein Text, eine Zahl oder ein Medien-Objekt ist. Das Template muss das wissen. * **Reservierte Namen.** Ein Feld, das in strapi `_sync` heißt, würde mit dem technischen Schlüssel kollidieren. Vermeiden Sie führende Unterstriche in Feldnamen. Wo die SEO-Angaben des Meta-Info-Plugins im mapping-Format stehen, ist noch nicht abschließend festgelegt. Klären Sie das für Ihren Shop mit Ihrem WEBSALE Ansprechpartner, bevor Sie [Schritt 7](#schritt-7-seo-felder-aus-meta-lesen) auf Basis des mapping-Formats umsetzen. Im schema-Format stehen sie in `meta`. ## Das schema-Format im Detail Jede Datei des schema-Formats beschreibt genau ein Dokument, beispielsweise die Seite „AGB". Jede Datei besteht aus drei Bestandteilen: | **Bestandteil** | **Inhalt** | **Details** | | --------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | `contentType` | Die technische Kennung der Eingabemaske, aus der das Dokument stammt. | [Die Hülle](#die-hulle) | | `meta` | Verwaltungsdaten wie IDs und Zeitstempel sowie die SEO-Angaben der Seite. | [Verwaltungsdaten und SEO-Felder in meta](#verwaltungsdaten-und-seo-felder-in-meta) | | `fields` | Die eigentlichen Inhalte, also die Werte aller Eingabefelder. | [Die Inhaltsfelder in fields](#die-inhaltsfelder-in-fields) | Diese drei Bestandteile zusammen werden "Hülle" genannt. Es handelt sich dabei um den äußeren Rahmen jeder Datei, der immer gleich aussieht. Auch dann, wenn Eingabemasken in Strapi verändert werden. Für die reine Migration genügt es, diesen Grundaufbau zu kennen. Die folgenden Unterabschnitte sind der Nachschlageteil für die konkrete Template-Anpassung. ### Die Hülle ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "contentType": "api::contentpage.contentpage", "meta": { … }, "fields": [ { "name": "…", "type": "…", "value": "…" } ] } ``` | **Schlüssel** | **Typ** | **Bedeutung** | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `contentType` | string | Quell-UID der Eingabemaske, beispielsweise `api::contentpage.contentpage`. Die UID hat die Form `api::.` und ist in strapi im Content-Type Builder sichtbar. | | `meta` | object | Von strapi bzw. der Sync-Middleware verwaltete Felder (siehe unten). | | `fields` | array | Die eigentlichen Inhaltsfelder, je `{ name, type, value }`. | Diese Hülle ist für alle Eingabemasken und Dokumente identisch. Das gilt auch, wenn Felder umbenannt, hinzugefügt oder gelöscht werden. Nur die Einträge innerhalb von `fields` ändern sich dadurch. ### Verwaltungsdaten und SEO-Felder in meta `meta` enthält die verwaltungsseitigen Felder eines Dokuments. Sie sind bewusst von den Inhaltsfeldern in `fields` getrennt: | **Feld** | **Typ** | **Hinweis** | | ------------------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | number | Interne numerische ID (pro Sprachversion). | | `documentId` | string | Stabile, sprachübergreifende Dokument-ID. Bestimmt standardmäßig den Dateinamen. | | `locale` | string | Sprache dieser Datei, beispielsweise `de`. Der Sprachcode entspricht nicht zwangsläufig dem Verzeichnisnamen im Shop (beispielsweise `Deutsch`); die Zuordnung ergibt sich aus der Subshop-Konfiguration. | | `createdAt` / `updatedAt` | string (ISO-8601) | Zeitstempel aus strapi. | | `publishedAt` | string oder null | `null` bei Entwürfen. | Ist für ein Dokument das Meta-Info-Plugin aktiv (siehe [SEO-Meta-Daten für CMS-Seiten](/strapi-cms/grundlagen-architektur-von-strapi#seo-meta-daten-fur-cms-seiten-meta-info-plugin)), enthält `meta` zusätzlich die SEO-Felder der Seite: | **Feld** | **Typ** | **Hinweis** | | ----------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `url` | string | SEO-URL der Seite. | | `metaTitle` | string | Meta-Title. | | `metaDescription` | string | Meta-Description. | | `robots` | string\[] | Ein Array, kein kommaseparierter String. Beispielsweise `["noindex", "nofollow"]`. | | `hreflang` | array | Verweise auf die sprachlichen Entsprechungen derselben Seite, für die hreflang-Angaben im HTML-Head. Wird automatisch berechnet, sobald das Meta-Info-Plugin aktiv ist. Enthält einen Eintrag pro Subshop, der diese Sprache bedient (`{ language, url, subshopId, default }`). | ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} "meta": { "id": 99, "documentId": "l9h00uvgblpjvlqqv1va9s44", "locale": "de", "createdAt": "…", "updatedAt": "…", "publishedAt": "…", "url": "agb", "metaTitle": "AGB", "metaDescription": "Allgemeine Geschäftsbedingungen", "robots": ["noindex", "nofollow"], "hreflang": [ { "language": "de", "url": "agb", "subshopId": "deutsch", "default": true } ] } ``` Eine Eingabemaske kann selbst Inhaltsfelder mit Namen wie `url` oder `robots` besitzen. Diese erscheinen dann als ganz normale Einträge in `fields` und sind etwas **anderes** als `meta.url` bzw. `meta.robots` (namensgleich, aber andere Bedeutung und teils andere Form). SEO-Werte aus dem Meta-Info-Plugin stehen immer in `meta` und niemals in `fields`. Verwechseln Sie beide beim Verarbeiten nicht. ### Die Inhaltsfelder in fields `fields` ist eine Liste aller Eingabefelder des Dokuments. Jeder Eintrag hat exakt drei Schlüssel: | **Schlüssel** | **Typ** | **Bedeutung** | | ------------- | -------------- | ------------------------------------------------------------------------------------------------------ | | `name` | string | Der technische Feldname, wie er aktuell in der Eingabemaske heißt (kann sich durch Umbenennen ändern). | | `type` | string | Der strapi Feldtyp (siehe [Feldtypen](#die-feldtypen)). | | `value` | je nach `type` | Der Wert. Die Form hängt vom Typ ab. | Zwei Reihenfolgen sind dabei zu unterscheiden: * **Reihenfolge der `fields`-Liste**: Sie folgt der Schema-Definition und ist fürs Rendern bedeutungslos. Greifen Sie deshalb immer über `name` und nie über die Position auf Felder zu. * Die **Reihenfolge innerhalb eines Array-Werts** (Inhaltsblöcke, wiederholbare Komponenten, Relationslisten) ist layoutkritisch. Sie entspricht exakt der Anordnung des Redakteurs und muss beim Rendern übernommen werden. ### Die Feldtypen **Skalare Typen**: `value` ist der Wert direkt. | **type** | **value** | | ---------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | `string` / `text` | string oder null | | `richtext` | string oder null (Markdown oder bereits konvertiertes HTML, je nach Einstellung der Sync-Middleware) | | `enumeration` | string oder null | | `boolean` | boolean oder null | | `integer` / `biginteger` / `decimal` / `float` | number oder null | | `date` / `datetime` / `time` / `timestamp` | string oder null | | `uid` | string oder null | | `json` | beliebiges JSON | | `blocks` | Array der strapi Blocks-Knoten oder HTML-String, je nach Einstellung der Sync-Middleware | Ob `richtext`- und `blocks`-Werte als Rohdaten (Markdown bzw. Blocks-JSON) oder als fertiges HTML ankommen, ist eine Deployment-Einstellung der Sync-Middleware. Klären Sie vor der Template-Anpassung mit WEBSALE, welche Variante für Ihren Shop aktiv ist. #### Medien im schema-Format **`media`**: `value` ist ein normalisiertes Medien-Objekt mit festen Schlüsseln (`url`, `alt`, `caption`, `name`, `mime`, `ext`, `width`, `height`, `size`, `formats`). Strapi-Interna wie IDs, Hashes, Provider-Daten und Zeitstempel sind bewusst entfernt, damit strapi-interne Änderungen daran nicht im Shop ankommen. Fehlt ein Wert, ist er `null`. Bei Mehrfach-Medien ist `value` ein Array solcher Objekte. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "logo", "type": "media", "value": { "url": "/uploads/websale_logo_576a45762c.webp", "alt": "Websale Firmenlogo", "caption": null, "name": "websale_logo.webp", "mime": "image/webp", "ext": ".webp", "width": 500, "height": 75, "size": 4.26, "formats": { "thumbnail": { "url": "/uploads/thumbnail_…", "width": 245, "height": 37, "mime": "image/webp", "size": 3.07 } } } } ``` #### Komponenten und Relationen **`component`**: `value` enthält eine eigene `fields`-Liste. Bei wiederholbaren Komponenten ist `value` ein Array solcher Objekte. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "button", "type": "component", "value": { "fields": [ { "name": "label", "type": "string", "value": "Mehr" }, { "name": "link", "type": "string", "value": "/info" } ] } } ``` **`dynamiczone`** (Inhaltsblöcke): `value` ist ein Array von Blöcken. Jeder Block trägt seinen Komponenten-Namen in `component`, seine `id` und eine eigene `fields`-Liste. ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "name": "content", "type": "dynamiczone", "value": [ { "component": "elemente.ws-markup", "id": 96, "fields": [ { "name": "Markup", "type": "richtext", "value": "AGB Content" }, { "name": "FullWidth", "type": "boolean", "value": false } ] } ] } ``` **`relation`**: `value` enthält die verknüpften Dokumente, rekursiv mit deren eigener `fields`-Liste. Eine Einzelrelation liefert ein Objekt, eine Mehrfachrelation ein Array. Die Auflösungstiefe ist begrenzt. Nicht mehr geladene tiefere Relationen erscheinen als `value: null`. Selbst-referenzierende Relationen (beispielsweise verschachtelte Navigationen) werden zusätzlich durch einen Zyklus-Schutz gekappt. Derselbe Typ wird pro Pfad nur einmal aufgelöst. Beachten Sie die Ladetiefe auch im Template: `$wsExternalData.load` schneidet über die Option `maxDepth` tief verschachtelte Strukturen ab. In den Beispielen dieser Seite steht `maxDepth: 20`. Siehe [\$wsExternalData](/frontend/referenz/module/wsexternaldata). ### Stabilitätsgarantie und ihre Grenze **Stabil ist die Struktur:** Egal was an den Eingabemasken passiert, jede Datei ist `{ contentType, meta, fields[] }` und jedes Feld `{ name, type, value }`. Darauf können sich Templates zu 100 % verlassen. **Nicht stabil ist die Bedeutung:** Benennt ein Redakteur ein Feld `title` in `titel` um, kommt das sauber durch. Im `name` steht dann aber `titel`. Ein Template, das gezielt nach `title` sucht, findet nichts mehr und gibt an dieser Stelle nichts aus. Die Zuordnung von Feldnamen zu ihrer Bedeutung ist eine Absprache zwischen Redaktion und Template-Verantwortlichen. Das Format kann dies nicht erzwingen. Einzige Ausnahme sind die SEO-Felder: Sie liegen über das Meta-Info-Plugin im schema-Format immer an derselben Stelle in `meta`, unabhängig davon, wie die Eingabemasken aufgebaut sind. ## Änderungen gegenüber der alten Struktur Die folgende Übersicht stellt die neue Struktur der alten Datenstruktur des bisherigen Content-Syncs gegenüber. Sie ist die Grundlage für die Template-Anpassung im nächsten Abschnitt. Die Spalte „Neue Struktur" zeigt das schema-Format. Die Änderungen bei der Kennung der Eingabemaske, der Komponenten-Kennung, den Medien, `localizations` und den Dateinamen gelten für **beide** Formate. Bei den SEO-Feldern ist nur die Ablage im schema-Format (`meta`) bestätigt; für das mapping-Format ist sie noch offen. | **Aspekt** | **Alte Struktur** | **Neue Struktur (schema)** | | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Hülle | `{ "id", "attributes": { …alle Felder… }, "content_type" }`
    Die Felder liegen in einem `attributes`-Wrapper. | `{ contentType, meta, fields[] }`
    Es gibt keinen `attributes`-Wrapper mehr. | | Kennung der Eingabemaske | kurzer Slug, beispielsweise `"contentpage"` | volle strapi-UID, beispielsweise `"api::contentpage.contentpage"` | | Komponenten-Kennung | `"__component"` | `"component"` (auf den einzelnen Inhaltsblöcken) | | Medien | REST-Wrapper `{ "data": { "id", "attributes": { … } } }` inklusive strapi-Interna | flaches, normalisiertes Medien-Objekt mit fester Schlüsselmenge (siehe oben) | | SEO-Felder | eigene Inhalts-Komponente (beispielsweise „Meta Information" mit `MetaTitle`, `MetaDescription`, `SeoURL`, `MetaRobots`), redaktionell in der Eingabemaske gepflegt | kein Inhaltsfeld mehr. Die Werte stehen über das Meta-Info-Plugin in `meta` mit neuen Namen: `SeoURL` → `url`, `MetaTitle` → `metaTitle`, `MetaDescription` → `metaDescription`, `MetaRobots` → `robots` (jetzt **Array** statt String). Neu hinzu kommt `hreflang`. | | `localizations` | immer vorhanden, auch leer | komplett entfernt | | Dateiname | inhaltlich abgeleitet und sprechend, beispielsweise `tpl_about.json` | standardmäßig `documentId`-basiert, beispielsweise `l9h00uvgblpjvlqqv1va9s44.json` | Die Umstellung der Dateinamen auf die `documentId` betrifft jede Stelle im Template, die eine JSON-Datei über einen sprechenden Namen lädt. Die `documentId` ist die zentrale, stabile Identität eines Dokuments. Die numerische `id` eignet sich dafür nicht, da sie pro Sprachversion wechselt. ## Templates migrieren: die acht Schritte Drei Hinweise vorab: 1. **Die Codebeispiele sind Muster zum Übertragen, kein Code zum unveränderten Kopieren.** Der Nachher-Code **ersetzt** die entsprechende bestehende Stelle in Ihrem Template – allerdings innerhalb der Testmodus-Weiche aus Schritt 2, sodass der bisherige Code für die Live-Ausgabe zunächst erhalten bleibt. 2. **Die Vorher-Beispiele zeigen ein typisches Muster der alten Struktur.** Da die alte Struktur je Shop unterschiedlich aufgebaut wurde, können die Stellen in Ihrem Shop abweichen. 3. **Arbeiten Sie von Anfang an hinter der Testmodus-Weiche** (Schritt 2). Sonst ändern Sie die Live-Ausgabe, bevor Sie sie geprüft haben. Die Beispiele verwenden durchgehend das schema-Format, weil dort der größere Umbau anfällt. Wo sich das mapping-Format unterscheidet, ist es im jeweiligen Schritt genannt. **Voraussetzung:** Die neuen Dateien müssen für Ihren Shop bereits erzeugt sein, sonst läuft der Testmodus ins Leere. Prüfen Sie im JSON-Verzeichnis, ob dort Dateien mit `documentId`-Namen liegen (`.json` und `.schema.json`). Die alten, sprechend benannten Dateien bleiben während der Umstellungsphase daneben erhalten. Aktivierung und Neuerzeugung veranlasst WEBSALE. ### Schritt 1: Betroffene Stellen finden **Wann nötig:** Immer. Suchen Sie im Template-Repository (GitLab) nach allen Stellen, an denen strapi-JSON geladen oder gelesen wird: * `$wsExternalData.load(` – lädt eine einzelne Datei. Relevant sind die Aufrufe mit der Option `source: "system"` und einem Pfad, der auf das JSON-Verzeichnis zeigt. * `$wsExternalData.read(` – liest ein Verzeichnis und liefert eine Liste von Dateinamen zurück. * die anschließenden Feldzugriffe auf die geladenen Daten, typischerweise erkennbar an `attributes` und `__component`. Ergebnis ist eine Liste der Templates, die in den folgenden Schritten angepasst werden. Notieren Sie zu jedem Treffer, welches strapi-Dokument dort geladen wird – die Zuordnung „Datei ↔ Dokument" brauchen Sie in Schritt 3. ### Schritt 2: Testmodus-Weiche einbauen **Wann nötig:** Immer, und zwar **vor** der ersten inhaltlichen Änderung. Für die Prüfung ist keine zweite strapi-Instanz nötig. Da die alten Dateien während der Umstellungsphase erhalten bleiben, liegen alte und neue Dateien nebeneinander im JSON-Verzeichnis. Sie können deshalb im selben Template zwischen alt und neu umschalten: Im [Testmodus](/frontend/referenz/module/wstestmode) lädt und rendert das Template die neuen Dateien, die Live-Ausgabe arbeitet unverändert weiter mit den alten. So ist die Migration jederzeit abgesichert. Die Live-Seite bleibt bis Schritt 8 unangetastet.

    Die Weiche umfasst nicht nur den Ladeaufruf, sondern den gesamten Ausgabeblock\*\*.\*\* Die Feldzugriffe der neuen Struktur (Schritte 4 bis 7) passen nicht auf die alten Dateien. Würden Sie nur den Dateinamen umschalten, wäre die Live-Ausgabe sofort leer. **Vorher (alte Struktur, ohne Weiche):** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cCMSLoadOptions = {"source": "system", "type": "json", "maxDepth": 20} }} {{ var $cCMSFile = ["json/Deutsch/tpl_about.json"] | join }} {{ var $cCMSData = $wsExternalData.load($cCMSFile, $cCMSLoadOptions) }} {{# … bisheriger Ausgabecode … #}} ``` **Nachher (mit Weiche – Gerüst, das Sie in den Schritten 3 bis 7 füllen):** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cCMSLoadOptions = {"source": "system", "type": "json", "maxDepth": 20} }} {{ if $wsTestMode.active }} {{# Testmodus: neue Struktur #}} {{ var $cCMSFile = ["json/Deutsch/l9h00uvgblpjvlqqv1va9s44.schema.json"] | join }} {{ var $cCMSData = $wsExternalData.load($cCMSFile, $cCMSLoadOptions) }} {{# … neuer Ausgabecode aus den Schritten 4 bis 7 … #}} {{ else }} {{# Live: bisherige Struktur, unverändert #}} {{ var $cCMSFile = ["json/Deutsch/tpl_about.json"] | join }} {{ var $cCMSData = $wsExternalData.load($cCMSFile, $cCMSLoadOptions) }} {{# … bisheriger Ausgabecode … #}} {{ /if }} ``` Alle folgenden Schritte arbeiten ausschließlich im oberen Zweig. Wie Sie den Testmodus im Shop aufrufen, steht unter [Testmodi des Shops ein-/ausschalten](/testmodi-des-shops-ein-ausschalten). Umfangreichere Templates werden mit einer Weiche pro Ausgabestelle unübersichtlich. In diesem Fall ist es praktikabler, das alte Ausgabe-Template unverändert zu lassen und die neue Fassung als eigene Datei zu pflegen, die nur im Testmodus eingebunden wird. Das Vorgehen dazu ist unter [Templates für strapi Inhalte anpassen](/strapi-cms/templates-fur-strapi-inhalte-anpassen) beschrieben. ### Schritt 3: Dateinamen in den Ladeaufrufen anpassen **Wann nötig:** Immer. **Der Pfad bleibt, nur der Dateiname ändert sich.** Die JSON-Dateien liegen weiterhin im selben Verzeichnis wie bisher: im JSON-Verzeichnis Ihres Shops, das die Templates über die Option `source: "system"` erreichen – beispielsweise `json/Deutsch/` für die deutschsprachigen Inhalte. Beide neuen Formate liegen dort **nebeneinander**, im selben Verzeichnis wie zuvor die alte Datei. Statt eines sprechenden Namens trägt jede Datei standardmäßig die `documentId` des Dokuments: | | **Vorher** | **Nachher** | | -------------- | ----------------------------- | --------------------------------------------------- | | mapping-Format | `json/Deutsch/tpl_about.json` | `json/Deutsch/l9h00uvgblpjvlqqv1va9s44.json` | | schema-Format | (gab es nicht) | `json/Deutsch/l9h00uvgblpjvlqqv1va9s44.schema.json` | **So finden Sie die `documentId`:** Öffnen Sie das Dokument in strapi im Content-Manager. Die `documentId` steht dann in der Adresszeile des Browsers. Zusätzlich steht sie in jeder erzeugten Datei des schema-Formats unter `meta.documentId`. *Screenshot: Content-Manager mit geöffnetem Dokument, `documentId` in der Adresszeile hervorgehoben.* **Wo Sie anpassen:** * In jedem `$wsExternalData.load(...)`-Aufruf, der eine strapi-Datei über ihren Namen lädt – im Gerüst aus Schritt 2 also der Wert von `$cCMSFile` im Testmodus-Zweig. * **Nicht** in `$wsExternalData.read(...)`-Aufrufen. Diese lesen ein Verzeichnis ein und bleiben unverändert. Wertet Ihr Template die eingelesenen Dateinamen danach aber inhaltlich aus – beispielsweise, um aus dem Namen die passende Seite abzuleiten –, muss diese Logik ebenfalls angepasst werden, denn die Namen sind nicht mehr sprechend. Am häufigsten übersehen: Mapping-Dateien und selbstgebaute Namenskonventionen. Wenn Ihr Template den Dateinamen erst zur Laufzeit zusammensetzt (beispielsweise aus der aufgerufenen URL über eine eigene Mapping-Datei), muss diese Zuordnung auf `documentId`-Dateinamen umgestellt werden. ### Schritt 4: Feldzugriffe umstellen **Wann nötig:** Immer. Der Umfang unterscheidet sich je nach Format. Gemeint ist die Stelle, die den Wert eines Eingabefelds aus den geladenen Daten liest – beispielsweise den Titel der Seite. **Beim mapping-Format** entfällt nur der `attributes`-Wrapper. Aus `$cCMSData.attributes.title` wird `$cCMSData.title`. Mehr ist an den Feldzugriffen nicht zu tun. **Beim schema-Format** liegen die Werte nicht mehr direkt unter ihrem Feldnamen, sondern als Einträge in der Liste `fields`. Überführen Sie diese Liste einmal in ein Name/Wert-Objekt. Danach greifen Sie wie gewohnt über den Feldnamen zu: Der Ladeaufruf aus Schritt 2 bleibt dabei unverändert. Ersetzt wird nur der Ausgabeteil darunter: **Vorher (alte Struktur):** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}

    {{= $cCMSData.attributes.title }}

    ``` **Nachher (schema-Format):** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ if $cCMSData }} {{# fields-Liste einmal in ein Name/Wert-Objekt überführen #}} {{ var $cFields = {} }} {{ foreach $cField in $cCMSData.fields }} {{ $cFields[$cField.name] = $cField.value }} {{ /foreach }}

    {{= $cFields.title }}

    {{ /if }} ``` Die Prüfung `{{ if $cCMSData }}` ist kein Beiwerk: `$wsExternalData.load` gibt `null` zurück, wenn die Datei fehlt oder ungültig ist. Ohne diese Prüfung bleibt die Seite ohne jeden Hinweis leer. Dieses Muster funktioniert auf jeder Ebene gleich: für die Felder des Dokuments, innerhalb von Komponenten (`value.fields`) und für die Blöcke der Inhaltsblöcke (siehe nächster Schritt). ### Schritt 5: Inhaltsblöcke (Dynamic Zone) anpassen **Wann nötig:** Wenn Ihr Template die Inhaltsblöcke einer Seite rendert. Das betrifft praktisch jede Inhaltsseite mit frei kombinierbaren Komponenten. Zwei Dinge ändern sich: * Die Komponenten-Kennung heißt jetzt `component` statt `__component` – das gilt für **beide** Formate. * Beim schema-Format liegen die Feldwerte eines Blocks in dessen eigener `fields`-Liste. Ersetzen Sie den bestehenden Render-Code nach diesem Muster: **Vorher (alte Struktur):** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $cItem in $cCMSData.attributes.content }} {{ if $cItem.__component == "elemente.ws-markup" }}
    {{! $cItem.Markup }}
    {{ /if }} {{ /foreach }} ``` **Nachher (mapping-Format):** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $cItem in $cCMSData.content }} {{ if $cItem.component == "elemente.ws-markup" }}
    {{! $cItem.Markup }}
    {{ /if }} {{ /foreach }} ``` **Nachher (schema-Format, `$cFields` aus Schritt 4):** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ foreach $cItem in $cFields.content }} {{ var $cItemFields = {} }} {{ foreach $cField in $cItem.fields }} {{ $cItemFields[$cField.name] = $cField.value }} {{ /foreach }} {{ if $cItem.component == "elemente.ws-markup" }}
    {{! $cItemFields.Markup }}
    {{ else }} {{# nicht umgesetzte Komponente: im Testmodus sichtbar machen #}} {{ if $wsTestMode.active }} {{ /if }} {{ /if }} {{ /foreach }} ``` Die Komponenten-Namen und Felder im Beispiel ersetzen Sie durch die Ihres Shops. Die Reihenfolge der Blöcke entspricht der Anordnung des Redakteurs und wird unverändert ausgegeben. Behalten Sie einen `{{ else }}`-Zweig für unbekannte Komponenten bei bzw. ergänzen Sie einen. Sonst verschwindet ein neu angelegter Block still aus der Seite, statt aufzufallen. ### Schritt 6: Medienzugriffe anpassen **Wann nötig:** Überall dort, wo Bilder oder Dateien aus strapi ausgegeben werden. Gilt für beide Formate. Der `data`/`attributes`-Wrapper um Medien entfällt. Bild-URL, Alternativtext und responsive Formate liegen direkt im normalisierten Medien-Objekt. Zusätzlich heißt der Alternativtext jetzt `alt` statt `alternativeText`. Ersetzen Sie die bestehenden Bild-Ausgaben nach diesem Muster: **Vorher (alte Struktur):** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $cCMSData.attributes.logo.data.attributes.alternativeText }} ``` **Nachher (schema-Format, `$cFields` aus Schritt 4):** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $cFields.logo.alt }} ``` **Nachher (mapping-Format):** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $cCMSData.logo.alt }} ``` Neu direkt verfügbar sind außerdem `width`, `height` und die responsiven Varianten unter `formats`, beispielsweise `$cFields.logo.formats.thumbnail.url`. Geben Sie diese Werte nur aus, wenn sie gefüllt sind: Fehlende Angaben stehen auf `null`, und es werden nicht für jeden Shop dieselben Formate erzeugt. ### Schritt 7: SEO-Felder aus `meta` lesen **Wann nötig:** Wenn Ihr Template Meta-Title, Meta-Description, Robots oder die SEO-URL aus den strapi-Daten ausgibt. Die Beispiele zeigen das schema-Format (zum mapping-Format siehe den Hinweis unter [Was Sie beim mapping-Format beachten müssen](#was-sie-beim-mapping-format-beachten-mussen)). Diese Werte stammten bisher aus einer Inhalts-Komponente (beispielsweise „Meta Information") und stehen künftig im Bereich `meta` der Datei, mit neuen Feldnamen (siehe [Gegenüberstellung](#anderungen-gegenuber-der-alten-struktur)). Ersetzen Sie die bestehenden Zugriffe nach diesem Muster: **Vorher (alte Struktur):** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $cCMSData.attributes.MetaInformation.MetaTitle }} ``` **Nachher (schema-Format):** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{= $cCMSData.meta.metaTitle }} ``` Zwei Punkte fallen dabei besonders auf: * **`robots` ist jetzt ein Array** und muss für die Ausgabe im Meta-Tag zu einem String zusammengefügt werden. `join` wird dafür mit Trennzeichen als Funktion aufgerufen; die Filter-Schreibweise `| join` in den Pfad-Beispielen dieser Seite fügt ohne Trennzeichen zusammen. * **Die SEO-Felder stehen in `meta`, nicht in `fields`.** Das Name/Wert-Objekt `$cFields` aus Schritt 4 enthält sie nicht. Neu verfügbar ist außerdem `meta.hreflang` mit einem Eintrag pro Subshop, der diese Sprache bedient. Wenn Sie hreflang-Tags ausgeben wollen, ist das die Datenbasis dafür. ### Schritt 8: Im Testmodus prüfen und live schalten **Wann nötig:** Immer, als letzter Schritt. Rufen Sie den Shop im Testmodus auf (siehe [Testmodi des Shops ein-/ausschalten](/testmodi-des-shops-ein-ausschalten)) und prüfen Sie jede migrierte Seite. *Screenshot: Shop im Testmodus mit einer migrierten Inhaltsseite.* Prüfliste: * Werden alle Inhaltsblöcke ausgegeben – und in der Reihenfolge, die der Redakteur in strapi gesetzt hat? * Erscheinen alle Bilder inklusive der responsiven Formate, mit Alternativtexten? * Stimmt die SEO-Ausgabe im HTML-Head: Meta-Title, Meta-Description, Robots? * Sind die Seiten über ihre SEO-URLs erreichbar? * Gibt es leere Stellen, an denen vorher Inhalt stand? Das ist der typische Hinweis auf einen Feldnamen, der nicht mehr passt. Vergleichen Sie dazu am besten Testmodus- und Live-Ausgabe derselben Seite direkt nebeneinander. Erst wenn alle Seiten geprüft sind, entfernen Sie die Weiche aus Schritt 2: Der Testmodus-Zweig wird zum regulären Code, der `{{ else }}`-Zweig mit dem alten Ladeaufruf und der alten Ausgabe entfällt. ## Wenn etwas nicht funktioniert | **Symptom** | **Wahrscheinliche Ursache** | **Prüfen** | | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Die Seite bleibt komplett leer, kein Inhalt aus strapi | Die Datei wurde nicht gefunden oder nicht geladen. `$wsExternalData.load` gibt in diesem Fall `null` zurück. | Dateiname und `documentId` prüfen (Schritt 3). Zur Fehlerursache liefert `$wsExternalData.getLastError()` einen Code, siehe [\$wsExternalData](/frontend/referenz/module/wsexternaldata). | | Einzelne Werte fehlen, der Rest der Seite steht | Der Feldname im Template passt nicht mehr zum Feldnamen in strapi. | Im schema-Format die `name`-Werte in `fields` mit den Feldnamen im Template vergleichen. | | Ein Inhaltsblock wird nicht ausgegeben | Die Komponenten-Kennung wird noch über `__component` geprüft, oder die Komponente ist im Template nicht umgesetzt. | Schritt 5, insbesondere den `{{ else }}`-Zweig für unbekannte Komponenten. | | Bilder fehlen oder haben keinen Alternativtext | Es wird noch über den alten `data`/`attributes`-Wrapper bzw. über `alternativeText` zugegriffen. | Schritt 6. | | Robots-Tag enthält etwas wie `noindexnofollow` | Das Array `meta.robots` wurde ohne Trennzeichen zusammengefügt. | Schritt 7. | | Tief verschachtelte Inhalte sind abgeschnitten | `maxDepth` im Ladeaufruf ist zu klein, oder eine Relation wurde von der Sync-Middleware nicht mehr aufgelöst (`value: null`). | Ladeoptionen und Abschnitt [Komponenten und Relationen](#komponenten-und-relationen). | Für den Umstellungstermin Ihres Shops sowie für die Aktivierung der Formate und die Neuerzeugung der Dateien für Bestandsinhalte (Backfill) wenden Sie sich an Ihren WEBSALE Ansprechpartner. # Templates für strapi Inhalte anpassen Source: https://dokumentation.websale.de/strapi-cms/templates-fur-strapi-inhalte-anpassen Anpassung der WEBSALE Shop-Templates an geänderte oder neue strapi Komponenten und Felder, inklusive Zugriff auf das Template-Repository in GitLab. Auf dieser Seite wird beschrieben, wie die Shop-Templates bei veränderten oder neuen strapi Komponenten oder Inhalte angepasst werden müssen. Diese Dokumentation richtet sich vorranging an Template-Manager und setzt Kenntnisse in HTML, CSS, JSON und der WEBSALE Template Engine voraus. *** ## Zugriff auf die Shop-Templates strapi definiert Struktur und Inhalte (Content-Types, Komponenten, Felder). Die Shop-Templates definieren, wie diese Inhalte im Shop dargestellt werden. Wenn sich in strapi etwas ändert (neue Komponente, neues Feld, Feld umbenannt), muss das entsprechende Shop-Template angepasst werden, da sonst ansonsten im Shop nichts, nicht vollständig oder falsch angezeigt wird. Um Templates anpassen zu können, benötigen Sie Zugriff auf das entsprechende Shop-Template-Repository in GitLab. Mehr Informationen dazu finden Sie [hier](/frontend/getting-started/arbeiten-mit-gitlab). In der Regel gibt es zwei Anwendungsfälle für die Anpassung von Templates: * **Bestehende Komponenten verändern** (Feld hinzugefügt/umbenannt/entfernt) * **Neue Komponenten hinzufügen** (Komponente existierte vorher nicht im Template) *** ## Bestehende Komponente wurde geändert Eine bestehende strapi-Komponente gilt als geändert, wenn z. B. ein Feld hinzugefügt, umbenannt oder entfernt wurde. Damit die Anpassung im Shop sichtbar wird, muss das Rendering im entsprechenden Template erweitert oder angepasst werden. ### Template ermitteln Wir empfehlen, pragmatisch über die Suche in [GitLab](/frontend/getting-started/arbeiten-mit-gitlab) vorzugehen, um das Template zu ermitteln, in dem die Anpassung vorgenommen werden muss. Suchen Sie zum Beispiel nach: * **Komponentenname** (z. B. `slider`, `imageLink`, `promoBanner`) * **Feldname** (z. B. `autoplayDelay`, `linkUrl`, `headline`) * **Komponentenkennung aus den JSON-Daten**, falls vorhanden (häufig z. B. `__component` oder eine Typ-/Slug-Angabe) Die Treffer führen Sie in der Regel zu einer Datei, in der die Komponente gerendert (Partial/Komponenten-Template), eingebunden (View-Template) oder zugeordnet (Mapping/Dispatcher) wird. Öffnen Sie die Datei anschließend in Ihrem Bearbeitungsprogramm, um mit der Anpassung fortzufahren. ### JSON-Datei ermitteln Damit Sie die Komponente später gezielt laden oder herunterladen können, müssen Sie die konkrete JSON-Datei identifizieren, in der die Komponentendaten gespeichert sind. Da die Komponente bereits im Shop verwendet wird, wird die dazugehörige JSON-Datei im Template in der Regel bereits an einer Stelle im Template geladen. Empfohlenes Vorgehen: * **Über das Template (schnellster Weg):** Suchen Sie im relevanten Template nach Stellen, an denen Daten geladen werden – typischerweise über `$wsExternalData.load(...)` (eine Datei) oder `$wsExternalData.read(...)` (Verzeichnis). Der dort verwendete `path` ist der Hinweis darauf, welche JSON-Datei(en) im Rendering verwendet werden. * **Über S3/Objektspeicher:** Laden Sie die Datei(en) aus dem relevanten Verzeichnis herunter und suchen Sie darin nach der Komponentenkennung (z. B. `content.imageLink` bzw. `__component`). So finden Sie heraus, in welcher Datei die Komponente tatsächlich enthalten ist. ### Publizierung im Testmodus Wenn Inhalte aus strapi zunächst nur im [Testmodus](/frontend/referenz/module/wstestmode) sichtbar sein sollen, kann die JSON in einem separaten Unterordner (z.B. `/test`) abgelegt werden. Im Template wird dann abhängig vom Testmodus der Pfad zur JSON-Datei umgestellt. Beispiel:\ Die JSON-Datei wird für Testinhalte zusätzlich in einem Unterordner `/test` abgelegt. Wenn der Testmodus aktiv ist (`$wsTestMode.active`), lädt das Template automatisch die Test-JSON aus diesem Unterordner. Dadurch können Anpassungen im Template oder neue / angepasste strapi-Komponenten getestet werden, ohne die Live-Ausgabe zu beeinflussen. ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $cCMSLoadOptions = {"source": "system", "type": "json", "maxDepth": 20} }} {{ var $cCMSFile = ["json/Deutsch/ws_start.json"] | join }} {{ if $wsTestMode.active }} {{ $cCMSFile = ["json/Deutsch/test/ws_start.json"] | join }} {{ /if }} {{ var $cCMSData = $wsExternalData.load($cCMSFile, $cCMSLoadOptions) }} ``` ### JSON prüfen Bevor Sie den Template-Code ändern, sollten Sie prüfen, wie die Komponente tatsächlich als Daten geliefert wird. Das hilft vor allem dabei, Tippfehler und falsche Annahmen über Feldnamen zu vermeiden. Je nach Setup gibt es dafür zwei übliche Wege: * **Ausgabe/Debug im Template**, z. B. an der Stelle, an der die Daten über `$wsExternalData.load(...)` verarbeitet werden. * **Download aus dem Objekt-/Dateispeicher (z. B. S3)**, sofern die generierten Dateien dort abgelegt werden und Sie Zugriff haben. Ziel ist, dass der Komponentenname und die Feldnamen eindeutig feststehen, bevor Sie das Rendering im Template erweitern. Weiterführende Informationen: * [\$wsExternalData - Externe Daten](/frontend/referenz/module/wsexternaldata) * [Externe Datenschnittstelle](/schnittstellen/externe-datenschnittstelle-datei-bucket-basiert) ### Beispiel: Komponente „Bild mit Link“ bekommt ein neues Feld In strapi existiert eine Komponente mit dem Namen `imageLink`. Diese Komponente besitzt zunächst die Felder `image` und `linkUrl`. **Datenübergabe JSON vor der Komponenten-Änderung** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "__component": "content.imageLink", "image": { "url": "/media/banner.jpg", "alt": "Banner" }, "linkUrl": "https://example.tld" } ``` Im Template wird die Komponente entsprechend gerendert, indem Bild und Link ausgegeben werden: **Template-Ausgabe vor der Komponenten-Änderung** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myVariable = $wsExternalData.load(["my-component.json"] | join, {"source":"system","type":"json","maxDepth":20}) }} $myVariable.image.alt ``` Nun wird die strapi-Komponente `imageLink` um ein weiteres Eingabefeld erweitert, z. B. `text`. Dadurch enthält die Datenstruktur zusätzlich den neuen Wert: **Datenübergabe JSON nach der Komponenten-Änderung** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "__component": "content.imageLink", "image": { "url": "/media/banner.jpg", "alt": "Banner" }, "linkUrl": "https://example.tld", "text": "Jetzt entdecken" } ``` Damit der Text im Shop angezeigt wird, muss das Template um die Ausgabe dieses Feldes ergänzt werden: **Template-Ausgabe nach der Komponenten-Änderung** ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myVariable = $wsExternalData.load(["my-component.json"] | join, {"source":"system","type":"json","maxDepth":20}) }} $myVariable.image.alt {{ $myVariable.text }} ``` Wenn bereits Inhalte existieren, die noch ohne das neue Feld gespeichert wurden, sollte das Template so angepasst werden, dass die Inhalte und das Feld nur ausgeben werden, wenn es vorhanden ist. So vermeiden Sie, dass ältere Inhalte beim Rendering unerwartet Probleme verursachen. Wenn Sie die Anpassung nicht direkt in der Live-Ansicht integrieren möchten, führen Sie die Anpassung zunächst im [Testmodus](/frontend/praxisbeispiele/testmodus) durch. *** ## Neue Komponente wurde angelegt ### Template auswählen oder Template anlegen Wenn eine neue Komponente in strapi angelegt wurde, gibt es zwei typische Ziel-Szenarien: * **Die neue Komponente soll auf einer bestehenden Seite angezeigt werden**\ Das Template dieser Seite öffnen und die Stelle auswählen, an der Inhalte/Komponenten gerendert werden (z. B. der Bereich, in dem Content-Blöcke ausgegeben werden). * **Die neue Komponente soll auf einer neuen Seite angezeigt werden**\ Ein neues [View-Template](/frontend/die-basics/template-theme) anlegen und dort das Laden und Rendern der Daten implementieren. ### JSON-Datei ermitteln Um die Inhalte der Komponente im Template ausgeben zu können, müssen Sie die JSON-Datei laden, in der die Komponentendaten gespeichert sind. Dazu muss der Dateiname bekannt sein. Empfohlene Wege, um den Dateinamen zu ermitteln: * **Über** `$wsExternalData.read(...)`**:**\ Wenn das Theme ein Verzeichnis per `read` einliest, kann darüber eine Dateiliste ausgegeben werden. So lässt sich der relevante Dateiname finden und anschließend gezielt per `load` laden. * **Über S3/Objektspeicher:**\ Wenn Zugriff auf S3 besteht, kann das relevante Verzeichnis geöffnet und die Datei(en) anhand Name/Struktur oder durch Suche nach der Komponentenkennung (z. B. `__component`) identifiziert werden. ### JSON-Daten prüfen Bevor das Rendering implementiert wird, sollte die JSON geprüft werden, damit eindeutig ist: * wie die Komponente heißt (z. B. `content.promoBanner`) * welche Felder geliefert werden (z. B. `image`, `linkUrl`, `text`) * wie verschachtelte Strukturen aussehen (z. B. Bildobjekt, Listen) Das verhindert Tippfehler und falsche Annahmen im Template. ### Beispiel neue Komponente integrieren Sie haben die JSON-Datei identifiziert, die die Daten Ihrer neuen Komponente enthält (z. B. `my-new-component.json`), und sich die Struktur bereits angesehen: **Datenübergabe JSON vor der Komponenten-Änderung** ```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "__component": "content.promoBanner", "image": { "url": "/media/banner.jpg", "alt": "Banner" }, "linkUrl": "https://example.tld" } ``` Um auf die Daten aus `my-new-component.json` zugreifen zu können, müssen Sie die Datei zuerst laden: ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ var $myVariable = $wsExternalData.load(["my-new-component.json"] | join, {"source":"system","type":"json","maxDepth":20}) }} ``` An der Stelle im Template, an der die Daten angezeigt werden sollen, geben Sie die Inhalte aus (vereinfacht): ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} {{ $myVariable.image.alt }} ``` Wenn Sie die Ausgabe nicht direkt in der Live-Ansicht integrieren möchten, führen Sie die Anpassung zunächst im Testmodus durch. *** ## Bildformate definieren Wenn das Layout genau eingehalten werden soll, sollten Bilder vor dem Upload in strapi in einem Bildbearbeitungsprogramm (z.B. Photoshop) gezielt zugeschnitten und auf die gewünschten Maße optimiert werden. Der Bildkonverter im Admin-Interface des Shops (unter Templates & Inhalte → Bildkonverter) sorgt anschließend dafür, dass das Bild komprimiert und optimiert wird. Für die Komprimierung und Optimierung im Bildkonverter können unter Bildkonverter → Bildformate entsprechende Profile angelegt werden, damit die Bilder nach den individuellen Wünschen des Anwenders bearbeitet werden. Um sicherzustellen, dass ein Bild auch korrekt angezeigt wird, wenn die Optimierung nicht das gewünschte Ergebnis ausliefert, kann man über feste Angaben im Template-Code einen Fallback einrichten. Zur Anpassung des Quellcodes verweisen wir hier auf [Gitlab](/frontend/getting-started/arbeiten-mit-gitlab). *** ## Weiterführende Informationen * [\$wsExternalData - Externe Daten](/frontend/referenz/module/wsexternaldata) * [Komponenten & Sammlungen in strapi](/strapi-cms/komponenten-sammlungen-in-strapi) # Datenfeed-Einrichtung Source: https://dokumentation.websale.de/ws-search/datenfeed-einrichtung Datenfeed im CSV-Format für das WEBSALE Such-Modul aufsetzen: Produktdaten, Kategorie-Spalten und Profile für effiziente Suchanfragen bereitstellen. Der Datenfeed bildet die Grundlage für die Such- und Filterfunktionen in Ihrem Onlineshop. Er liefert die benötigten Produktdaten an die Such-Datenbank und ermöglicht so eine effiziente Verarbeitung der Suchanfragen. In diesem Abschnitt erfahren Sie, wie der Datenfeed für Ihr Such-Modul eingerichtet wird und welche Informationen standardmäßig enthalten sind. *** ## Grundlegendes ### Allgemeines * Der Datenfeed wird im **CSV-Format** erstellt. * **Pro Subshop** wird ein separater Datenfeed benötigt. * Hinweis: Je nach gebuchtem Datenfeed-Paketumfang können zusätzliche Kosten anfallen, falls ein Upgrade auf ein höheres Paket erforderlich wird. * Die **Spaltennamen** im Datenfeed entsprechen den **technischen Feldnamen** der Produktdatenfelder. * Die Kategorie-Spalten im Datenfeed werden wie folgt benannt: * `AllCategories`: Spalte für die Kategorienamen. * `CatIDs`: Spalte für die Kategorie-Indexe. * `AllCatIDs`: Spalte für die technische Darstellung aller Kategorie-Indexe. ### Einrichtung sowie Anpassung und Erweiterung des Datenfeeds Die Einrichtung des Datenfeeds kann eigenständig erfolgen, sofern ein entsprechendes Produkt-Feed-Profil bereitgestellt wurde. Die benötigten Profile werden durch das WEBSALE Support Team zur Verfügung gestellt und können bedarfsgerecht konfiguriert werden. Sofern keine eigene Umsetzung gewünscht ist, übernimmt das WEBSALE Support Team die vollständige Einrichtung. Anpassungen und Erweiterungen des Datenfeeds sind ebenfalls eigenständig möglich, sofern Zugriff auf das zugehörige Export-Template besteht. Alternativ können Änderungen komfortabel über das WEBSALE Anfrageportal beauftragt werden. ### Datenfelder und Einstellungen im Standard Im Standard sind Datenfelder und Einstellungen definiert, die für die meisten Shops geeignet sind. Falls Abweichungen oder zusätzliche Felder benötigt werden, können diese bei der Beauftragung im **WEBSALE Anfrageportal** übermittelt werden. #### Dateiname des Datenfeeds Der Dateiname des Datenfeeds wird standardmäßig nach folgendem Schema gebildet: `ShopID-SubshopID.csv` **Beispiel:** * **ShopID:** meinshop * **SubshopID:** deutsch * **Dateiname:** meinshop-deutsch.csv ### Abhängigkeit von der Konfiguration des Such-Moduls Im Datenfeed können nur die Felder verwendet werden, die zuvor bei der Konfiguration des Such-Moduls aktiviert wurden. Falls zusätzliche Felder benötigt werden, muss die Konfiguration des Such-Moduls entsprechend angepasst werden. *** ## Standard-Datenfelder im Datenfeed Der Datenfeed enthält die folgenden Felder im Standard-Template. Diese Felder werden rein ausgegeben. Die Konfiguration, ob ein Feld durchsucht, gefiltert oder sortiert werden kann, erfolgt separat in der Konfiguration des Such-Moduls. Die Standard-Datenfelder im Datenfeed haben wir zum besseren Verständnis in die folgenden Gruppen unterteilt. ### Technische Datenfelder Diese Felder werden vom Such-Modul benötigt, um die Suchfunktion auszuführen und die Ergebnisse korrekt den passenden Produkten zuzuordnen. Sie sind Pflichtfelder und müssen immer im Datenfeed enthalten sein. | **Feldname** | **Beschreibung** | | --------------- | ------------------------------------------------------------------------------------------ | | `ProdIndexBase` | Basis-Produktindex (technischer Parameter) | | `AllCategories` | Liste der Kategorien (ganzer String) | | `CatIDs` | Aktueller Kategorieindex, in dem das Produkt gefunden wurde beziehungsweise zugewiesen ist | | `AllCatIDs` | Technische Struktur aller Kategorie-Indexe, Kategoriepfad | ### Produktdatenfelder Diese Felder enthalten die Produkteigenschaften und Produktinformationen, die durchsucht oder nach denen gefiltert und sortiert werden sollen. Sie sind erweiterbar und können durch zusätzliche Datenfelder ergänzt werden, um weitere Funktionen oder Suchoptionen zu ermöglichen. | **Feldname** | **Beschreibung** | | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Number` | Produktnummer | | `Name` | Produktname | | `Descr` | Produktbeschreibung | | `Price` | Produktpreis | | `OrgPrice` | Original-Preis, also der Preis vor der Reduzierung | | `CreationDate` | Anlagedatum vom Produkt (Unix-Timestamp) | | | Information, ob das Produkt neu ist
    Wird die Information in einem anderen Produktdatenfeld übergeben, muss dies bei der Konfiguration angegeben werden. | | `PR-SalesRank` | Information, ob das Produkt ein TopSeller ist (Verkaufsrang) | | `PR-RatingScore(min, max)` | Information über die Bewertung des Produkts.
    Im Standard wird die WEBSALE Produktbewertung verwendet. | | *\* | Alle Varianten und Ausführungen der Produkte, beispielsweise Farbe oder Größe | ### Datenfelder für Verfügbarkeit der Produkte Wird die Lagerbestandsverwaltung im Onlineshop genutzt, berücksichtigt das Such-Modul standardmäßig nur Produkte, die: * **Einen Bestand größer als 0** haben oder * Deren **Lagerstatus nicht auf „rot"** steht Diese Einstellungen gewährleisten, dass den Nutzern im Onlineshop nur tatsächlich verfügbare Produkte angezeigt werden, was die Benutzerfreundlichkeit und Kaufbereitschaft erhöht. Im Onlineshop kann ein **Filter für die Verfügbarkeit** bereitgestellt werden. Dieser ermöglicht es den Nutzern, auch Produkte anzuzeigen, die: * **Einen Bestand kleiner oder gleich 0** haben oder * Deren **Lagerstatus auf „rot"** steht | **Feldname** | **Beschreibung** | | ------------------ | ---------------------------------------------- | | `Inventory-Active` | Prüfung, ob Lagerbestandsverwaltung aktiv ist | | `Inventory-Type` | Typ der Bestandsverwaltung, dynamisch oder fix | | `Inventory` | Tatsächlicher Bestand | | `StoreID` | Lagerartikelnummer aus dem ERP | ### Beispiel eines Datenfeed-Templates v8s Das folgende Beispiel zeigt, wie ein typisches CSV-Datenfeed-Template aufgebaut sein kann: ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} Number~t~ ProdIndexBase~t~ IsBaseProduct~t~ Name~t~ Price~t~ OrgPrice~t~ Descr~t~ CreationDate~t~ Inventory-Active~t~ Inventory-Type~t~ Inventory~t~ StoreID~t~ AllCategories~t~ CatIDs~t~ AllCatIDs~t~ Varianten-Attribut-1 (Beispiel Farbe)~t~ Varianten-Attribut-2 (Beispiel Groesse)~n~ {@PR-Articles} ~PR-Number~~t~ ~PR-ProdIndex~~t~ {!PR-IsDepVarProduct}yes{/!PR-IsDepVarProduct}~t~ ~PR-Name~~t~ ~PR-Price~~t~ ~PR-OrgPrice~~t~ ~PR-Descr~~t~ ~PR-CreationDate~~t~ {!PR-Inventory}yes{/PR-Inventory}{!PR-Inventory}no{/!PR-Inventory}~t~ {!PR-Amount}dynamic{/PR-Amount}{!PR-Amount}static{/!PR-Amount}~t~ ~PR-Amount~~t~ ~PR-StoreId~~t~ {@Cat-AllAssigned}{@Cat-Names}~Cat-Name~{!last}/{/!last}{/@Cat-Names}{!last}>{/!last}{/@Cat-AllAssigned}~t~ {@Cat-AllAssigned}~Cat-Index~{!last}>{/!last}{/@Cat-AllAssigned}~t~ {@Cat-AllAssigned}{@Cat-Data}~Cat-Index~{!last}/{/!last}{/@Cat-Data}{!last}>{/!last}{/@Cat-AllAssigned}~t~ ~PR-Farbe~~t~ ~PR-Groesse~~n~ {/@PR-Articles} ``` *** ## Standard-Einstellungen für den Datenfeed Der Datenfeed wird mit vordefinierten Standardeinstellungen erstellt, die für die meisten Shops geeignet sind. Diese Einstellungen regeln, welche Daten exportiert werden und wie der Export erfolgt. Nachfolgend sind die wichtigsten Standard-Einstellungen sowie optionale Anpassungen aufgeführt. Die hier aufgeführten Einstellungen, beispielsweise Filter für Sichtbarkeit oder Bestellbarkeit, sind Teil des **Produkt-Feed-Profils beziehungsweise Export-Templates** und werden **nicht direkt im Admin Interface** konfiguriert. Sie können eigenständig angepasst werden, sofern Zugriff auf das zugehörige Export-Template besteht. Alternativ können Änderungen über das [WEBSALE Anfrageportal](https://websale.atlassian.net/servicedesk/customer/portals) beauftragt werden. **Beispiel:** Damit auch aktuell nicht sichtbare oder nicht bestellbare Produkte im Feed enthalten sind, müssen die Filter *„Nur Produkte exportieren, die … sichtbar sind"* und *„… bestellbar sind"* im Export-Template auf `Nein` gesetzt werden. ### Einstellungen für Produkte | **Konfiguration** | **Einstellung** | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | | **Abhängige Variationen (als eigenständige Produkte) exportieren**
    Variationen eines Produkts, beispielsweise Größen oder Farben, werden als separate Einträge im Feed exportiert. | Ja | | **Zusätzlich Stammdaten exportieren**
    Diese Einstellung steuert, ob bei der Nutzung von Varianten-Produkten neben den spezifischen Varianten-Informationen auch die Informationen des zugehörigen Stammartikels in den Datenfeed aufgenommen werden sollen. Dies ist besonders relevant für Shops, die in den Stammdaten zusätzliche Informationen hinterlegen, die in den Varianten nicht enthalten sind. | Ja | | **Nur Produkte exportieren, die zum Zeitpunkt des Exports im Shop sichtbar sind**
    Diese Einstellung legt fest, dass nur Produkte in den Datenfeed aufgenommen werden, die im Shop als sichtbar gelten. Wenn die Einstellung deaktiviert ist, werden alle Produkte exportiert, unabhängig von ihrer Sichtbarkeit.
    - **Sichtbarkeitszeitraum:** Produkte, die außerhalb der festgelegten Zeiträume („Sichtbar von" und „Sichtbar bis") liegen, gelten als nicht bestellbar und werden bei aktivierter Einstellung nicht in den Datenfeed aufgenommen. | Nein | | **Nur Produkte exportieren, die zum Zeitpunkt des Exports bestellbar sind**
    Die Bestellbarkeit eines Produkts wird nach den folgenden Kriterien geprüft:
    - **Varianten-Produkte:** Ein Produkt gilt als bestellbar, wenn mindestens eine zugehörige Variante bestellbar ist. Solche Produkte werden bei aktivierter Einstellung in den Datenfeed aufgenommen.
    - **Feld „Bestellbar":** Produkte, bei denen das Feld „Bestellbar" auf „Nein" steht, gelten als nicht bestellbar und werden bei aktivierter Einstellung nicht in den Datenfeed aufgenommen.
    - **Lagerbestandsampel:** Produkte, deren Lagerbestandsampel auf „Rot" steht, einschließlich „red-soft" und „red-hard", gelten als nicht bestellbar. Wenn die Konfiguration des Such-Moduls so eingestellt ist, dass nur lieferbare Produkte angezeigt werden, können Produkte mit einem Lagerbestandsampelstatus „Rot" zwar im Datenfeed enthalten sein, werden jedoch standardmäßig in der Suche und Filterung nicht berücksichtigt. Die Unterscheidung zwischen „red-soft" und „red-hard" spielt dabei keine Rolle. | Nein | | **HTML-Tags aus Produktdaten entfernen**
    HTML-Formatierungen werden aus den Produktdaten entfernt, um eine saubere Ausgabe zu gewährleisten. | Ja | | **Zeilenumbrüche entfernen**
    Entfernt Zeilenumbrüche aus den Produktdaten, um Formatierungsfehler zu vermeiden. | Ja | ### Einstellungen für Kategorien | **Konfiguration** | **Einstellung** | | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | | **Im Shop-Menü ausgeblendete Kategorien exportieren**
    Kategorien, die im Menü nicht sichtbar sind, werden dennoch im Feed exportiert, da sie trotzdem im Shop genutzt werden. | Ja | | **Nur Kategorien exportieren, bei denen das Feld „PricePush" auf „ja" steht**
    Diese Einstellung steuert, ob nur Kategorien in den Datenfeed aufgenommen werden sollen, die in den Importdaten ausdrücklich für den Export freigegeben wurden, oder ob alle Kategorien unabhängig von dieser Markierung berücksichtigt werden. | Nein | | **Nur Kategorien exportieren, deren Robot-Einstellungen „noindex" nicht aktiv sind**
    Kategorien, die nicht für Suchmaschinen ausgeschlossen sind, werden in den Datenfeed aufgenommen. Die Einstellung erfolgt im TopRank Manager. | Nein | | **Nur Produkte einer Kategorie exportieren, deren Robot-Einstellungen für Produkte „noindex" nicht aktiv sind**
    Diese Einstellung steuert, ob nur Produkte in den Datenfeed aufgenommen werden sollen, die Kategorien zugeordnet sind, deren Importdaten eine Indexierung erlauben, oder ob alle Produkte unabhängig von dieser Einstellung berücksichtigt werden. | Nein | ### Allgemeine Formatierung | **Konfiguration** | **Einstellung** | | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | | **ISO-Format**
    Erstellt den Feed im ISO-Format, das auch für den Subshop eingestellt ist. Die Einstellung erfolgt über die Shop-Konfiguration shop.config. | 3-stelliger ISO-Code | ### Zeitsteuerung des Exports Die Zeitsteuerung legt fest, wie oft der Datenfeed aktualisiert wird. Je nach Art der Produktpflege oder Importmethode des Shops können folgende Einstellungen verwendet werden: | **Konfiguration** | **Einstellung** | | -------------------------------------------------------------------------------------------------------------------------------- | ----------------- | | **Datenfeed-Export nach Artikelimport Pro**
    Einstellung für Shops, die Artikelimport Pro nutzen | Nach jedem Import | | **Datenfeed-Export nach Artikelimport**
    Einstellungen für Shops mit automatischem Import, ohne Artikelimport Pro | 1 Mal am Tag | | **Datenfeed-Export nach individueller Zeitangabe**
    Einstellungen für Shops mit manueller Pflege oder anderen Importformaten | 2 Mal am Tag | ### Trigger-URL und Token für automatisches Einlesen des Datenfeeds in die WEBSALE | search Datenbank Damit der Datenfeed automatisch in die Datenbank von WEBSALE | search eingelesen werden kann, wird eine sogenannte Trigger-URL verwendet. Diese URL wird durch einen individuellen Token abgesichert, der von WEBSALE bereitgestellt wird. **Aufbau Trigger URL** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://-trigger.search.websale.net/ ``` * ``: Ihre individuelle Shop-ID, wird von WEBSALE vergeben. * ``: Ein eindeutiger Sicherheitstoken, der von WEBSALE generiert und zur Verfügung gestellt wird. **Beispiel** * ShopID: `meinshop` * Token: `957caL8CBT2BWQVuQStJe7GVH` * separates Triggern je SubShop mit Zusatz `/SubShopID`, beispielsweise `/01-aa` ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} http://meinshop-trigger.search.websale.net/957caL8CBT2BWQVuQStJe7GVH/SubShopID ``` Die Angabe der `SubShopID` direkt nach dem Token ist erforderlich, da sie sicherstellt, dass der Versatz zwischen den Importvorgängen der einzelnen SubShops minimiert wird. Wird die `SubShopID` in der URL nicht angegeben, werden automatisch alle Datenfeeds aller SubShops importiert, was zu erhöhtem Datenvolumen und potenziellen Überschneidungen nach einem Import führen kann. *** ## Datenfeeds für Content-Quellen Der bisher beschriebene Datenfeed liefert Produktdaten und wird im Dataflow Manager erzeugt. Inhalte aus anderen Systemen laufen dagegen über einen eigenen Weg. Betreiben Sie beispielsweise einen Blog oder ein Magazin außerhalb des Shops, können Sie deren Inhalte über einen externen Datenfeed in die Suche aufnehmen. Diese Feeds erzeugt das jeweilige Quellsystem, nicht der Dataflow Manager. WEBSALE | search liest sie über eine URL ein. Der Import von Content-Feeds steht ab den Plugin-Versionen **elasticsearch\_manager v1.15.0** und **websale\_search v1.18.0** zur Verfügung. **Anforderungen an den Feed** * Unterstützte Formate sind CSV, TSV und JSON. * Der Feed muss pro Eintrag drei Informationen enthalten, nämlich die URL der Seite, den Titel und den Textinhalt. * Die Spaltennamen sind frei wählbar. Weichen sie von `source`, `title` und `content` ab, ordnen Sie sie in der Konfiguration über `field_mapping` zu. * Pro Subshop und Quelle wird ein eigener Feed benötigt, analog zum Produktfeed. Die Einbindung erfolgt im Importmodul über `source: feed`. Alle Parameter dazu finden Sie im Abschnitt [Mehrere Content-Quellen für die Suche](/ws-search/konfiguration-des-such-moduls#mehrere-content-quellen-für-die-suche). *** ## Anpassungen und zusätzliche Datenfelder Falls Abweichungen vom Standard-Template oder zusätzliche Datenfelder benötigt werden, können diese über das **WEBSALE Anfrageportal** beauftragt werden. Änderungen werden durch das WEBSALE Support Team umgesetzt und erfordern eine Prüfung, ob die gewünschten Felder bereits in der Konfiguration des Such-Moduls aktiviert wurden. # Integration in die Templates (Storefront) Source: https://dokumentation.websale.de/ws-search/integration-in-die-templates-storefront Voraussetzungen und Überblick zur Einbindung des Such-Moduls in WEBSALE Shop-Templates: Aktivierung, Suchparameter, Datenfeed und WebComponents. ## Voraussetzungen Bevor Sie mit der Integration des Such-Moduls in die Shop-Templates beginnen, stellen Sie sicher, dass die folgenden Schritte bereits abgeschlossen sind: 1. **Aktivierung der Funktion** * Die Funktion muss über das **WEBSALE Anfrageportal** aktiviert worden sein. Details zur Aktivierung finden Sie im Abschnitt [Aktivierung des Moduls](/ws-search/integration-in-die-templates-storefront). 2. **Konfiguration des Such-Moduls** * Die Suchparameter, wie die durchsuchbaren Felder, Prioritäten und Relevanzen, müssen konfiguriert sein. Details dazu entnehmen Sie bitte dem Abschnitt [Konfiguration des Such-Moduls](/ws-search/integration-in-die-templates-storefront). 3. **Bereitstellung des Datenfeeds** * Ein Datenfeed basierend auf den konfigurierten Suchfeldern muss erstellt und bereitgestellt sein. Dies erfolgt über den **Dataflow Manager**. Informationen dazu finden Sie im Abschnitt [Datenfeed-Einrichtung](/ws-search/integration-in-die-templates-storefront). Nur wenn diese Voraussetzungen erfüllt sind, kann die Integration des Such-Moduls in die Templates erfolgreich durchgeführt werden. ## Übersicht * [Suche & Suchergebnisseite](/ws-search/integration-in-die-templates-storefront/suche-suchergebnisseite) — Diese Dokumentation beschreibt die Integration und Nutzung der Suchfunktionen des Moduls WEBSALE | search in einen WEBSALE Onlineshop. Sie umfasst die Einrichtung des Sucheingabefeldes (mit oder ohne Suggestfunktion), die Anzeige von Suchergebnissen sowie die After-Search-Navigation zur Filterung und Sortierung der Ergebnisse. * [Filtern & Sortieren auf Kategorien](/ws-search/integration-in-die-templates-storefront/filtern-sortieren-auf-kategorien) — Das Modul WEBSALE | search ermöglicht nicht nur die klassische Produktsuche, sondern kann auch zur Filterung und Sortierung auf Kategorieseiten genutzt werden. Dadurch können Kunden die angezeigten Produkte gezielt nach Kriterien wie Farbe, Preis oder Verfügbarkeit eingrenzen und in einer gewünschten Reihenfolge anzeigen lassen. * [JavaScript-Bundles](/ws-search/integration-in-die-templates-storefront/javascript-bundles) — Auf dieser Seite sind die JavaScript-Bundles dokumentiert, die für die Integration des Suchmoduls in die Templates (Storefront) erforderlich sind. Die Bundles werden von WEBSALE versioniert bereitgestellt (z. B. über die WEBSALE JavaScript-Bibliothek bzw. das WEBSALE PageSpeed-Tool) und müssen im Template mit der passenden Versionskennung eingebunden werden. * [WebComponents](/ws-search/integration-in-die-templates-storefront/webcomponents) — Die WEBSALE WebComponents sind wiederverwendbare Bausteine, die von WEBSALE bereitgestellt werden. Sie generieren automatisch Quellcode für HTML und CSS und erleichtern die Integration komplexer Funktionen wie Suche, Filterung oder Paginierung in die Storefront-Templates. # URL-Filterparameter und Query-Parameter der Suche Source: https://dokumentation.websale.de/ws-search/integration-in-die-templates-storefront/webcomponents/url-filterparameter-query-parameter URL-Filterparameter und Query-Parameter steuern Filterauswahl, Sortierung und Pagination der Such- und Kategorieseiten teilbar und bookmarkfähig. Das Such-Modul von WEBSALE | search unterstützt neben der klassischen `filter_eq[]`-Notation auch erweiterte Vergleichsoperatoren zur dynamischen Filterung über die URL. Diese Funktion eignet sich besonders für das Direktverlinken von gefilterten Listen, z. B. in Teasern, Landingpages oder Marketing-Kampagnen. ## Allgemeine Syntax der URL-Parameter Filter können über die URL direkt an das Suchmodul übergeben werden. **Struktur der Filter-Parameter** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} filter_[]= ``` **Beispiel für das Setzen eines Farbfilters** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} filter_eq[farbe]=beige ``` **Parameter in einer vollständigen URL** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www.ihr-shop.de/c/name-der-kategorie?filter_eq[farbe]=beige ``` **Erweiterung der URL um Preisfilter** Zeigt alle Produkte mit einem Preis **zwischen 10 € und 20 €**. ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://www.ihr-shop.de/c/name-der-kategorie?filter_eq[farbe]=beige&filter_gte[price]=10&filter_lte[price]=20 ``` ## Unterstützte Filteroperatoren | **Parameter** | **Bedeutung** | **Beschreibung** | | ------------------- | --------------------------- | ------------------------------------- | | `filter_eq[field]` | equal (`=`) | Exakte Übereinstimmung | | `filter_neq[field]` | not equal (`≠`) | Schließt Werte aus | | `filter_gte[field]` | greater than or equal (`≥`) | Filtert Werte **größer oder gleich** | | `filter_lte[field]` | less than or equal (`≤`) | Filtert Werte **kleiner oder gleich** | Um im Chip visuell darauf hinzuweisen, dass es sich um einen negativen Filter handelt, kann das Attribut `neq-label` in `` verwendet werden. Mehr dazu in der Dokumentation zu der [Komponente ws-filter-chip](/ws-search/integration-in-die-templates-storefront/webcomponents/ui-komponenten/ws-filter-chip). ## Automatische Filter-Initialisierung beim Seitenaufruf Beim Aufruf einer Seite werden Filter aus den URL-Parametern automatisch gesetzt und die Suche wird automatisch ausgeführt. Damit funktionieren Deep-Links zu gefilterten Suchergebnissen ohne zusätzliches Template-JavaScript. **Beispiel** ```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} https://test.shop.websale.net/kategorie/unterkategorie?filter_eq[brand]=nike&filter_eq[color]=red ``` Beim Aufruf dieser URL passiert automatisch Folgendes: * Der Filter `brand` wird auf den Wert `nike` gesetzt, der Filter `color` auf `red`. * Der **URL-Pfad** (`/kategorie/unterkategorie`) wird als Kategorie-Filter verwendet. * Die Filter-UI wird automatisch vorbelegt: Bei `eq`-Filtern werden die entsprechenden Optionen angehakt (Checkbox-, Image- und Label-Filter, inklusive statischer Optionen); Range-Filter setzen Slider und Eingabefelder auf die übergebenen Werte. * Die Suche wird automatisch mit den gesetzten Filtern ausgeführt. Die automatische Filter-Initialisierung ist ab `ws-search-component-1.9.1.js` nativ in den WebComponents enthalten. In älteren Versionen musste dieses Verhalten über ein JavaScript im Template umgesetzt werden (siehe [Filtern & Sortieren auf Kategorien](/ws-search/integration-in-die-templates-storefront/filtern-sortieren-auf-kategorien)). # Konfiguration des Such-Moduls Source: https://dokumentation.websale.de/ws-search/konfiguration-des-such-moduls Importmodul und Suchmodul von WEBSALE | search abstimmen: Datenbereitstellung, Stoppwörter, Filterregeln und Laufzeitverhalten der Shop-Suche steuern. Die Konfiguration des Suchmoduls ist derzeit noch nicht direkt im OSB verfügbar, weder über eine grafische Oberfläche noch über eine Code-basierte Eingabe. Aktuell kann die Einrichtung ausschließlich über WEBSALE vorgenommen werden. In Kürze wird die Möglichkeit zur **Konfiguration per Code** bereitgestellt. Wir bitten bis dahin noch um etwas Geduld und informieren Sie, sobald diese Option zur Verfügung steht. Bis dahin teilen Sie bitte Ihre gewünschten Einstellungen Ihrem WEBSALE-Ansprechpartner mit, damit die Anpassungen im Suchmodul für Sie vorgenommen werden können. Diese Seite führt Sie vom Zusammenspiel der beiden Module über die Konfigurationshierarchie bis zu den einzelnen Parametern. Zuerst klären wir, welche Aufgabe Importmodul und Suchmodul jeweils haben. Danach folgt der Aufbau der Konfiguration in drei Ebenen. Im Anschluss werden die Einstellungen des Importmoduls beschrieben, zum Schluss die des Suchmoduls. *** ## Importkonfiguration & Konfiguration des Suchmoduls Damit das Suchmodul WEBSALE | search korrekt funktioniert, müssen sowohl das zugehörige Importmodul („Bereitstellen") als auch das Suchmodul selbst konfiguriert werden. Beide Bereiche sind eng miteinander verknüpft, erfüllen jedoch unterschiedliche Aufgaben. ### Importmodul der Suche Im Importmodul werden die **Daten für die Suche bereitgestellt**. Hier wird definiert, welche Daten importiert und verfügbar gemacht werden, beispielsweise Produkt- und Kategoriedatenfelder, JSON-Dateien für Inhalte wie AGB, Kontakt oder FAQ, Stoppwörter und andere Suchparameter. Es reicht jedoch nicht aus, die Daten lediglich bereitzustellen. Im Suchmodul selbst muss zusätzlich konfiguriert werden, ob und wie diese Daten berücksichtigt werden sollen. Werden die bereitgestellten Daten im Suchmodul nicht aktiviert oder eingebunden, haben sie keinen Einfluss auf die Suchfunktion. ### Suchmodul Im Suchmodul wird festgelegt, wie die bereitgestellten Daten bei der Suche im Shop berücksichtigt werden, also zur Laufzeit. Das bedeutet, dass beispielsweise importierte Stoppwörter, Filterregeln oder Datenfelder aktiv in der Such- und Filterlogik verwendet werden. Erst die Kombination aus bereitgestellten Daten (Importmodul) und deren Aktivierung im Suchmodul stellt sicher, dass die gewünschte Suchkonfiguration vollständig und wirksam ist. *** ## Datenfeed im Dataflow Manager Der Datenfeed bildet die Grundlage für das Importmodul. Der Datenfeed wird im Onlineservicebereich des [DataflowManagers](https://websale.atlassian.net/wiki/spaces/Doku/pages/2124972064/DataFlowManager) erstellt und enthält alle Produktinformationen, die im Suchindex berücksichtigt werden. Über den Datenfeed werden sämtliche Produktdaten bereitgestellt, die durchsucht, gefiltert oder sortiert werden sollen. Dazu müssen im Dataflow Manager alle relevanten Produktfelder enthalten sein, beispielsweise Name, Beschreibung, Kategorien, Preis, Lagerbestand und Attribute. Das Importmodul greift anschließend auf diesen Feed zu und wandelt die enthaltenen Daten in das interne JSON-Format für den Elasticsearch-Index um. *** ## Konfigurationshierarchie (ab v1.12.x / v.1.11.x) Die nachfolgend beschriebene Konfigurationshierarchie steht ab den Plugin-Versionen **websale\_search v.1.12.x** und **elasticsearch\_manager v1.11.x** zur Verfügung. Die Merge-Logik gilt für Suchmodul und Importmodul gleichermaßen. Ab diesen Versionen unterstützen beide Module eine dreistufige Konfigurationshierarchie: `global_configs` → `language_configs` → `subshop_configs`. Dadurch können Einstellungen einmalig auf globaler Ebene definiert und bei Bedarf auf Subshop-Ebene gezielt überschrieben werden. So lassen sich Redundanzen in der Konfiguration vermeiden. Auf der obersten Ebene (Top-Level) werden grundsätzlich nur Infrastruktur-Aliase definiert, beispielsweise für Datenbankverbindungen oder Index-Namen. Diese werden über YAML-Aliase (`*name`) in die untergeordneten Blöcke eingebunden. Aktuell gibt es hiervon noch Ausnahmen. Im `elasticsearch_manager` wird `datafeed` weiterhin direkt auf Top-Level-Ebene konfiguriert. In `websale_search` gilt das gleiche für `filter_config` und `suggest_config`. Alle übrigen Einstellungen folgen dem dreistufigen Modell über `global_configs`, `language_configs` und `subshop_configs`. ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} x-database: &database base_url: http://websale-search-es-connector-es-http:9200 connections_per_node: 15 timeout: 30 retries: 10 retry_timeout: true x-keydb: &keydb host: websale-search-keydb-connector port: 6379 mapping: deutsch: 0 englisch: 1 x-indices: &indices product: product category: category completion: completion content: content statistics: statistics_data archive: statistics_archive suggest: aggregated_statistics ``` ### Globale Konfiguration (`global_configs`) `global_configs` bildet das unterste Level der Hierarchie. Hier definierte Werte gelten für alle Subshops, es sei denn, sie werden auf einer übergeordneten Ebene überschrieben. **Suchmodul** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} database: *database keydb: *keydb indices: *indices global_configs: search_config: {...} fields_config: {...} suggest_config: {...} filter_config: {...} language_configs: {...} subshop_configs: {...} ``` **Importmodul** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} database: *database keydb: *keydb indices: *indices global_configs: variant_fields: {...} index_configs: {...} language_configs: {...} subshop_configs: {...} ``` ### Sprachkonfiguration (`language_configs`) `language_configs` bildet das mittlere Level der Hierarchie. Hier können Konfigurationen für Sprachgruppen definiert werden, die für alle Subshops dieser Sprache gelten. Sie können nur durch explizite Subshop-Konfigurationen überschrieben werden. **Suchmodul** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} language_configs: de: lemmatization: {...} stopwords_filter: {...} fuzzy_filter: {...} punctuation_filter: {...} en: lemmatization: {...} stopwords_filter: {...} fuzzy_filter: {...} punctuation_filter: {...} ``` **Importmodul** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} language_configs: de: lemmatization: {...} stopwords: {...} synonyms: {...} en: lemmatization: {...} stopwords: {...} synonyms: {...} ``` ### Subshop-Konfiguration (`subshop_configs`) `subshop_configs` bildet das höchste Level der Hierarchie. Hier kann jeder Konfigurationsparameter für einen einzelnen Subshop explizit überschrieben werden. Der Key `language` in den `subshop_configs` verknüpft den jeweiligen Subshop mit dem zu seiner Sprache zugehörigen `language_configs`-Block. **Suchmodul** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} subshop_configs: deutsch: language: de # lädt die Config "de" aus language_configs keyword_mappings: {...} wssearchdata_mappings: {...} englisch: language: en # lädt die Config "en" aus language_configs keyword_mappings: {...} wssearchdata_mappings: {...} ``` **Importmodul** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} subshop_configs: deutsch: language: de # lädt die Config "de" aus language_configs datafeed_url: https://www.example-datafeed.de/example/download/path/file-deutsch.csv englisch: language: en # lädt die Config "en" aus language_configs datafeed_url: https://www.example-datafeed.de/example/download/path/file-englisch.csv ``` *** ## Konfiguration des Importmoduls ### Datenfeed-Konfiguration Die Zuordnung und Verarbeitung des Feeds wird im Abschnitt `datafeed` der Konfiguration des Importmoduls festgelegt. Hier werden Format, Encoding, Speicherpfade und die Feldzuweisungen definiert, die der Suchindex beim Import benötigt. **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} datafeed: format: csv encoding: ISO-8859-1 chunk_size: 1000 dir_path: /data/subshop_data remove_na_values: true new_product_days: 365 invalid_docs_max: 0 log_percent: 10 product_id: number base_id: prodindexbase is_base_product: isbaseproduct creation_date: creationdate api_store_id: StoreId es_store_id: storeid inventory: inventory inventory_active: inventory-active inventory_type: inventory-type category_str: allcategories category_ids: catids all_category_ids: allcatids category_separator: "/" value_separator: ">" field_separator: "\t" index_category_hierarchy: false normalize_negative_prices: true ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `format` | Dateiformat des Datenfeeds, beispielsweise `csv`. Aktuell wird nur `csv` unterstützt. | | `encoding` | Zeichencodierung des Feeds, beispielsweise `ISO-8859-1`. In der V8s werden aktuell nur ISO-Codierungen unterstützt, `utf-8` wird nicht unterstützt. | | `chunk_size` | Anzahl der Zeilen pro Verarbeitungsschritt (Chunk). Standardwert: `1000`. | | `dir_path` | Pfad für die automatisch generierten temporären JSON-Dateien, die beim Import als Zwischenspeicher dienen, beispielsweise `/data/subshop_data`.
    Der Pfad wird bei der Einrichtung des Suchmoduls durch WEBSALE angegeben und kann nicht geändert werden. | | `remove_na_values` | Entfernt ungültige oder leere Werte aus dem Feed.
    - `true` → Leere oder ungültige Werte werden beim Import entfernt.
    - `false` → Werte bleiben erhalten und werden in Elasticsearch importiert. | | `new_product_days` | Legt fest, wie viele Tage ein Produkt nach seiner Erstellung als „neu" gilt, beispielsweise `365`. Diese Information wird benötigt, um Sortierungen oder Filter nach „neuesten Produkten" zu nutzen. | | `invalid_docs_max` | Maximale Anzahl fehlerhafter Zeilen, bevor der Importprozess abgebrochen wird. Der Wert `0` bedeutet, dass der Prozess bei der ersten fehlerhaften Zeile stoppt.
    Damit der Prozess fortgeführt werden kann, müssen die Fehler behoben werden. | | `log_percent` | Schwelle in Prozent, bei der der Fortschritt des Imports geloggt wird. Der Wert `10` bedeutet, dass nach jeweils 10 % der verarbeiteten Daten ein Log-Eintrag erfolgt.
    Die Logs stehen zum aktuellen Zeitpunkt nur der WEBSALE AG zur Verfügung und können bei Bedarf beziehungsweise auf Anfrage zugesendet werden. | | `product_id` | CSV-Spaltenname, der auf das Produktdatenfeld mit der eindeutigen Produktnummer zeigt. Es muss der technische Feldname des Produktdatenfelds angegeben werden, das die Produktnummer enthält, beispielsweise `number`. | | `base_id` | Basis-Produkt-ID. Es muss der technische Feldname des Produktdatenfelds angegeben werden, das die Basis-Produktnummer enthält, beispielsweise `prodindexbase`. | | `is_base_product` | Es muss der technische Feldname des Produktdatenfelds aus dem Datenfeed angegeben werden, das die Information enthält, ob es sich um ein Basisprodukt handelt. | | `creation_date` | Es muss der technische Feldname des Produktdatenfelds aus dem Datenfeed angegeben werden, das den Timestamp der Erstellung des Produktes enthält. | | `api_store_id` | Name der Lagerbestands-ID aus der [REST Lagerbestand](https://websale.atlassian.net/wiki/spaces/Doku/pages/1819869432/REST+Lagerbestand) Schnittstelle, beispielsweise `StoreId`. | | `es_store_id` | Lagerbestands-ID im Suchindex. Es muss der technische Feldname des Produktdatenfelds aus dem Datenfeed angegeben werden, das diese Information enthält, beispielsweise `storeid`. | | `inventory` | Gibt den Lagerbestand eines Produktes an.
    Es muss der technische Feldname des Produktdatenfelds aus dem Datenfeed angegeben werden, das diese Information enthält, beispielsweise `inventory`. | | `inventory_active` | Gibt an, ob ein Produkt die Lagerbestandsverwaltung aktiviert hat.
    Es muss der technische Feldname des Produktdatenfelds aus dem Datenfeed angegeben werden, das diese Information enthält, beispielsweise `inventory-active`. | | `inventory_type` | Angabe, ob die Lagerbestandsverwaltung statisch oder dynamisch ist.
    Es muss der technische Feldname des Produktdatenfelds aus dem Datenfeed angegeben werden, das diese Information enthält, beispielsweise `inventory-type`. | | `category_str` | Enthält alle Kategorie-Strings (Kategorienamen) eines Produkts.
    Ist das Produkt nur einer Kategorie zugewiesen, ist es nur der eine Kategoriename. Bei mehreren Kategoriezuweisungen können alle übergeben werden.
    Es muss der technische Feldname des Datenfelds aus dem Datenfeed angegeben werden, das diese Information enthält, beispielsweise `allcategories`. | | `category_ids` | Enthält die Kategorie-IDs des Produktes.
    Ist das Produkt nur einer Kategorie zugewiesen, ist es nur ein Index. Bei mehreren Kategoriezuweisungen können alle Indexe übergeben werden.
    Es muss der technische Feldname des Datenfelds aus dem Datenfeed angegeben werden, das diese Information enthält, beispielsweise `catids`. | | `all_category_ids` | Enthält *alle* Kategorie-IDs des Produkts inklusive des Breadcrumbs, wenn ein Produkt mehreren Kategorien zugewiesen ist.
    Ist das Produkt nur einer Kategorie zugewiesen, ist es nur ein Index. Bei mehreren Kategoriezuweisungen können alle Indexe übergeben werden.
    Es muss der technische Feldname des Datenfelds aus dem Datenfeed angegeben werden, das diese Information enthält, beispielsweise `allcatids`. | | `category_separator` | Liegen Produkte in mehreren Kategorien, muss hier das Trennzeichen angegeben werden, beispielsweise `/`, um die Daten korrekt voneinander zu trennen. | | `value_separator` | Trennzeichen für mehrwertige Inhalte pro Feld, beispielsweise der Breadcrumb-Trenner für die Kategorie oder die Inhaltsstoffe bei Nahrungsmitteln. Beim Import werden die Werte des Feldes anhand dieses Separators in einzelne Einträge gesplittet. Das Trennzeichen muss mit der Feed-Erzeugung abgestimmt sein. Es darf nicht ungekennzeichnet im eigentlichen Wert vorkommen, stellen Sie dafür bei Bedarf Escaping oder Quoting im Feed sicher. | | `field_separator` | Zeichen, das die Spalten im CSV-Datenfeed voneinander trennt. Standard ist der Tabulator (TAB), empfohlen für Tab-CSV-Dateien. Andere Trennzeichen wie `;` oder `,` sind möglich, müssen aber mit der tatsächlichen Feed-Struktur übereinstimmen. | | `index_category_hierarchy` | Legt fest, ob das Importmodul die Kategorie-Hierarchie automatisch aufbaut. Bei `true` reicht es, wenn Produkte nur in der untersten Kategorie eingeordnet sind, sie werden dann auch in übergeordneten Kategorien gefunden. Bei `false` wird die Hierarchie nicht automatisch erstellt. Gilt global für alle Subshops.
    Default: `false` | | `normalize_negative_prices` | Aktiviert oder deaktiviert die Normalisierung negativer Preise. Wenn aktiviert, werden negative Preise auf 0.0 normalisiert. | ### Subshopkonfiguration im Importmodul In diesem Abschnitt werden alle subshopspezifischen Einstellungen für das Importmodul definiert. Jeder Subshop wird dabei als eigener Konfigurationsblock unter dem Abschnitt `subshop_configs` angelegt. Über diese Konfiguration wird festgelegt, welche Daten je Subshop importiert und bereitgestellt werden. Dadurch kann das Suchmodul später pro Subshop gezielt auf die entsprechenden Daten zugreifen und die Suche individuell steuern. **Standardkonfiguration für den Subshop Deutsch** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} subshop_configs: deutsch: nlp_lang: de datafeed_url: http://content..websale.net/search/websale_search.csv variant_fields: enabled: true fields: - color - size index_configs: product: enabled: true custom_fields: - name: keyword_field123 type: keyword - name: template_field456 type: template - name: timestampcreatedat type: date format: strict_date_optional_time||epoch_second - name: float_field789 type: double category: enabled: true custom_fields: - name: cat_descr type: template custom_config: search_fields: - field: cat_str boost: 2 - field: cat_str_path boost: 1.5 display_fields: - field: cat_id - field: cat_id_path - field: cat_str - field: cat_str_path content: ... completion: enabled: true fields: - name: name validate: False - name: descr validate: True stopwords: {...} # siehe Abschnitt „Toleranz für das Ignorieren von Stoppwörtern (stopwords)" synonyms: {...} # siehe Abschnitt „Synonyme (synonyms)" lemmatization: {...} # siehe Abschnitt „Grammatikalische Flexion (lemmatization)" englisch: {...} ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `nlp_lang` | Der Parameter `nlp_lang` legt fest, in welcher Sprache die textuelle Aufbereitung der Suchdaten erfolgt.
    Dabei werden sprachspezifische Modelle und Regeln aus den NLP-Bibliotheken [spaCy](https://spacy.io/) und [Simplemma](https://adbar.github.io/simplemma/) verwendet.
    Diese sorgen dafür, dass die Suchdaten während des Imports sprachgerecht analysiert und verarbeitet werden, beispielsweise im Hinblick auf Wortstämme, Grundformen (Lemmata) und Stoppwörter.
    Aktuell verfügbare Sprachen:
    - Deutsch (`de`) = Standard
    - Englisch (`en`)
    - Spanisch (`es`)
    - Französisch (`fr`)
    - Italienisch (`it`)
    - Niederländisch (`nl`)
    - Portugiesisch (`pt`)
    - Dänisch (`da`)
    - Tschechisch (`cs`)
    - Polnisch (`pl`)
    - Finnisch (`fi`)
    - Indonesisch (`id`)
    - Slowakisch (`sk`)
    - Türkisch (`tr`)
    - Schwedisch (`sv`)
    - Norwegisch Bokmål (`nb`) | | `datafeed_url` | URL des Datenfeeds. Wird vom WEBSALE Support eingerichtet und bereitgestellt. | | `variant_fields` | Liste der technischen Produktdatenfelder, die Varianten eines Produktes beschreiben, beispielsweise Farbe (`color`) oder Größe (`size`). Siehe Abschnitt [Variant Fields](#variantenfelder-für-filter-variant_fields). | | `enabled` | Verknüpft beim Import Basis-Produkte und ihre Varianten. | | `fields` | Technische Namen der Variantenfelder eines Produkts, immer in Kleinbuchstaben. | | `index_configs` | Indexspezifische Konfigurationen. | | `product` | Hauptindex für die Produktsuche. Enthält die Produktdatenfelder für den Suchindex. | | `enabled` | Aktiviert die Erstellung dieses Index im Import. | | `custom_fields` | Individuell definierte Produktdatenfelder, die zusätzlich in den Suchindex aufgenommen werden. Angabe des technischen Namens des Produktdatenfeldes. | | `name` | Technischer Name des Produktdatenfeldes, immer in Kleinbuchstaben. | | `type` | Datentyp des Feldes. Verfügbare Typen: `text`, `keyword`, `integer`, `float`, `double`, `date`, `boolean`, `template`.
    `template` ist ein spezieller Feldtyp für Textfelder, die sowohl durchsuchbar als auch filterbar sein sollen. | | `category` | Index für die Kategoriesuche. Ermöglicht es, Kategorien als eigenständigen Index zu durchsuchen. Wenn beim Import ein Kategorie-Index angelegt wurde, kann dieser in der Konfiguration des Suchmoduls aktiviert werden. | | `enabled` | Aktiviert die Erstellung beziehungsweise Nutzung dieses Index. Muss sowohl in der Import-Konfiguration als auch in der Suchmodul-Konfiguration auf `true` gesetzt werden. | | `custom_fields` | Individuell definierte Felder, die zusätzlich in den Kategorie-Index aufgenommen werden sollen, analog zu `product`. Siehe Abschnitt custom\_fields des Produktindex. Im Default sind nur die Standard-Kategoriefelder enthalten (IDs und Name). Jedes Feld wird mit `name` (technischer Feldname, immer Kleinbuchstaben) und `type` (Datentyp, beispielsweise `text`, `keyword` oder `template`) angegeben. | | `custom_config` | Konfigurationsblock für die Kategoriesuche. Hier wird festgelegt, welche Felder durchsucht und welche in der Antwort zurückgegeben werden. Dieser Key wird für zukünftige zusätzliche Indizes analog übernommen. | | `search_fields` | Liste der Felder, die bei einer Kategoriensuche durchsucht werden, analog zu `product`. Sollte immer mindestens die Felder `cat_str` und `cat_str_path` enthalten. Pro Feld kann ein `boost`-Wert angegeben werden, um die Gewichtung zu steuern. | | `field` | Technischer Name des zu durchsuchenden Feldes. Per Default verfügbar: `cat_str`, `cat_str_path`. | | `boost` | Gewichtungsfaktor für das Feld bei der Suche. Höhere Werte erhöhen die Relevanz von Treffern in diesem Feld. | | `display_fields` | Liste der Felder, die in der Suchantwort zurückgegeben werden, analog zu `product`. Benötigt wird mindestens `cat_id`. Per Default verfügbare Felder: `cat_id`, `cat_id_path`, `cat_str`, `cat_str_path`. | | `field` | Technischer Name des Feldes, das in der Antwort enthalten sein soll. | | `content` | Hauptindex für die Suche über Inhaltsseiten wie Impressum, Datenschutz oder AGB.
    Mehr Informationen dazu finden Sie im Abschnitt [content](#inhaltsseiten-in-den-suchindex-aufnehmen). Sollen mehrere Content-Quellen durchsucht werden, siehe Abschnitt [Mehrere Content-Quellen für die Suche](#mehrere-content-quellen-für-die-suche). | | `completion` | Index für Vorschläge (Autocomplete beziehungsweise Autovervollständigung). | | `enabled` | Aktiviert die Erstellung dieses Index im Import. | | `fields` | Liste der Produktdatenfelder aus dem Suchindex, die für Vorschläge verwendet werden. | | `stopwords` | Definition der Stoppwort-Liste.
    Mehr Informationen dazu finden Sie im Abschnitt [stopwords](#toleranz-für-das-ignorieren-von-stoppwörtern-stopwords).
    Mehr Informationen zur Aktivierung der Funktion im Suchmodul finden Sie im Abschnitt [stopwords\_filter](#toleranz-für-das-ignorieren-von-stopwörtern-stopwords_filter). | | `synonyms` | Definition manueller Synonymlisten.
    Mehr Informationen dazu im Abschnitt [synonyms](#synonyme-synonyms). | | `lemmatization` | Konfiguration der grammatikalischen Flexionen.
    Mehr Informationen dazu finden Sie im Abschnitt [lemmatization](#grammatikalische-flexion-lemmatization).
    Mehr Informationen zur Aktivierung der Funktion im Suchmodul finden Sie im Abschnitt [lemmatization](#grammatikalische-flexion-lemmatization-2). | #### Toleranz für das Ignorieren von Stoppwörtern (stopwords) Stoppwörter sind wenig aussagekräftige Wörter, beispielsweise Artikel oder einfache Präpositionen, die bei der Auswertung von Suchanfragen ignoriert werden können, um irrelevante Übereinstimmungen zu reduzieren. Ob diese Ignorierlogik zur Laufzeit angewendet wird, steuert das Suchmodul. Welche Wörter als Stoppwörter behandelt, ausgenommen (Whitelist) oder zusätzlich aufgenommen (Blacklist) werden, definiert das Importmodul. In diesem Abschnitt wird festgelegt, wie die Suchfunktion mit häufig vorkommenden, bedeutungsarmen Wörtern („Stoppwörtern") umgeht. Als Grundlage dient die Standardliste von spaCy, die gängige Funktionswörter wie *der, die, das, mit, von* enthält. Für optionale Whitelist- und Blacklist-Einträge kann diese Liste individuell angepasst werden: * Die Whitelist entfernt Wörter aus der spaCy-Stoppwortliste, sodass sie nicht ignoriert und bei der Suche berücksichtigt werden. * Die Blacklist fügt Wörter zur spaCy-Liste hinzu, sodass sie bei der Suche ausgefiltert werden. Wird ein Wort blackgelistet, das bereits enthalten ist, bleibt die Wirkung unverändert. Optional kann eine eigene `.txt`-Datei mit Stoppwörtern verwendet werden. Soll diese extern hinterlegt werden, beispielsweise auf einem Kundensystem, ist eine technische Abstimmung zur Einbindung der Datei erforderlich. Damit die konfigurierten Stoppwörter im Suchprozess tatsächlich berücksichtigt werden, muss im **Suchmodul** der Parameter `stopwords_filter.enabled: true` aktiviert sein. Siehe Abschnitt „Stoppwort-Filter im Suchmodul". **Standardkonfiguration** `stopwords` ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} stopwords: path: "" # optional: Pfad zu eigener .txt, sonst spacy-Default whitelist: # Begriffe, die NICHT als Stopwort behandelt werden sollen - mit # wichtig für Produktausprägungen, beispielsweise Jacke mit Kapuze - ohne # wichtig für Tiernahrung, beispielsweise ohne Getreide - für # wichtig für Zielgruppen, beispielsweise für Damen - in # wichtig für Farben und Größen, beispielsweise in Blau, in 40 - und # wichtig für Kombinationen, beispielsweise Huhn und Reis blacklist: # zusätzliche Stopwörter, die entfernt werden sollen - der - die - das - ein - eine - einer - eines - einem - einen - bei - nach - von - zu - zum - zur - auch - oder ``` **Parameterbeschreibung** `stopwords` | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `path` | Pfad zu einer eigenen `.txt`-Datei mit Stoppwörtern (ein Wort pro Zeile), beispielsweise `/data/stopwords_de.txt`.
    Wird keine Datei angegeben, wird die Standardliste von [spaCy](https://spacy.io/) verwendet. | | `whitelist` | Wörter, die **nicht** als Stoppwort behandelt werden sollen, also Ausnahmen von der Standardliste.
    Eignet sich für fachlich relevante Begriffe wie „mit", „ohne", „für", „in" oder „und". | | `blacklist` | Zusätzliche Wörter, die als Stoppwort **entfernt** werden sollen, also eine Ergänzung zur Standardliste von [spaCy](https://spacy.io/).
    Typisch sind Artikel und Präpositionen wie „der", „die", „das", „ein", „eine", „einer", „eines", „einem", „einen", „bei", „nach", „von", „zu", „zum", „zur", „auch" und „oder". | Die Funktion muss zusätzlich noch für das [Suchmodul](#toleranz-für-das-ignorieren-von-stopwörtern-stopwords_filter) aktiviert werden. #### Synonyme (synonyms) Die Synonymfunktion ermöglicht es, Begriffe in der Suche miteinander zu verknüpfen. Dadurch erscheinen bei der Eingabe eines Begriffs auch Treffer zu gleichbedeutenden oder verwandten Begriffen. Synonyme können entweder bidirektional („Jacke" = „Jacket") oder unidirektional („Turniersakko" → „Turnierjacke") definiert werden. Optional lassen sich Synonymlisten als Datei hinterlegen oder direkt in der Konfiguration pflegen. Im Standard sind keine Synonyme hinterlegt. Die Funktion wird aktiv, sobald entweder eine Synonymliste (`path`) angegeben oder manuelle Synonyme (`clouds`) definiert werden. **Beispielkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} synonyms: path: "" clouds: - src: # Beispiel 1 - trenchcoat - kutte - caban - janker target: - mantel - jacke mode: bi - src: # Beispiel 2 - kängoro - kängguhru - kengooroo target: känguru mode: uni ``` * **Beispiel 1 (`mode: bi`)** Die Begriffe *„trenchcoat"*, *„kutte"*, *„caban"*, *„janker"*, *„mantel"* und *„jacke"* sind bidirektional miteinander verknüpft. Eine Suche nach einem dieser Begriffe führt auch zu Treffern, die einen der anderen Begriffe enthalten. Beispielsweise liefert eine Suche nach *„Janker"* auch Ergebnisse mit *„Mantel"* oder *„Trenchcoat"*, und umgekehrt. * **Beispiel 2 (`mode: uni`)** Die Begriffe *„kängoro"*, *„kängguhru"* und *„kengooroo"* werden einseitig auf den Begriff *„känguru"* gemappt. Eine Suche nach einer der Schreibvarianten führt zu Treffern mit *„känguru"*, nicht jedoch umgekehrt. Dieser Modus eignet sich vor allem für Tippfehler, Schreibvarianten oder vereinheitlichte Begriffe. **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `path` | Optional kann eine TXT-Datei mit Synonymen hinterlegt werden (ein Wort pro Zeile). Beim Parameter wird der Pfad der `txt`-Datei angegeben, beispielsweise `/data/synonyms_de.txt`.
    Änderungen an der Datei erfordern eine Neuindexierung.
    Falls die Datei extern hinterlegt werden soll, beispielsweise auf einem Server des Kunden, ist eine gesonderte technische Abstimmung erforderlich, um den Zugriff auf diese Datei sicherzustellen. | | `clouds` | Liste mit manuell definierten Synonymgruppen. Jede Gruppe beschreibt eine Beziehung zwischen Quell- und Zielbegriffen. | | `src` | Quellbegriffe, die ersetzt oder verknüpft werden sollen. Kann als einzelner String oder als Liste angegeben werden. | | `target` | Zielbegriffe, auf die verwiesen wird. Kann als einzelner String oder als Liste angegeben werden. | | `mode` | Verknüpfungsmodus:
    - `uni` → unidirektional. Nur `src → target`, das heißt bei Eingabe von `src` wird nach `target` gesucht, nicht umgekehrt.
    - `bi` → bidirektional. Alle Begriffe innerhalb von `src` und `target` gelten gegenseitig als Synonyme. | **Hinweis:** Nach Änderungen an Synonymen muss die Datenfeed-Generierung manuell gestartet werden, damit eine Neuindexierung erfolgt. #### Grammatikalische Flexion (lemmatization) In diesem Abschnitt wird festgelegt, ob und für welche Felder grammatikalische Wortformen beim Import auf ihre Grundform reduziert werden. Dadurch erkennt die Suche auch sprachliche Varianten, etwa dass „rote Hemden", „rotes Hemd" oder „Hemd in Rot" denselben Begriff meinen. Die Funktion verbessert die sprachliche Erkennung und sorgt für natürlichere Suchergebnisse. Sie sollte für beschreibende Textfelder aktiviert werden, beispielsweise *name* oder *descr*. Für technische Felder wie *product\_id* oder *sku* sollte sie deaktiviert bleiben. **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} lemmatization: enabled: true language: de fields: - name - descr ``` * Die grammatikalische Grundform-Erkennung ist aktiviert (`enabled: true`). * Es wird die deutsche Sprachlogik verwendet (`language: de`). * Die Felder `name` und `descr` werden beim Import auf ihre Grundformen reduziert. * Dadurch erkennt die Suche auch grammatikalisch oder in der Wortstellung abweichende Begriffe, beispielsweise „rotes Hemd" und „Hemd in Rot". **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | Aktiviert (`true`) oder deaktiviert (`false`) die grammatikalische Reduktion von Suchbegriffen auf ihre Grundform.
    Grundlage sind die sprachspezifischen Wortstämme und Modelle der NLP-Bibliotheken [*spaCy*](https://spacy.io/) und [Simplemma](https://adbar.github.io/simplemma/).
    Bei deaktivierter Einstellung erfolgt eine wortgenaue Suche ohne sprachliche Vereinheitlichung. | | `language` | Definiert die Sprache, für die der Lemmatizer angewendet wird. Aktuell verfügbar:
    - Deutsch (`de`) = Standard
    - Englisch (`en`)
    - Spanisch (`es`)
    - Französisch (`fr`)
    - Italienisch (`it`)
    - Niederländisch (`nl`)
    - Portugiesisch (`pt`)
    - Dänisch (`da`)
    - Tschechisch (`cs`)
    - Polnisch (`pl`)
    - Finnisch (`fi`)
    - Indonesisch (`id`)
    - Slowakisch (`sk`)
    - Türkisch (`tr`)
    - Schwedisch (`sv`)
    - Norwegisch Bokmål (`nb`)
    Je nach gewählter Sprache werden die entsprechenden Sprachmodelle von [*spaCy*](https://spacy.io/) genutzt, um grammatikalische Varianten korrekt zu erkennen. | | `fields` | Legt fest, welche Datenfelder aus dem Import sprachlich analysiert und lemmatisiert werden. Es müssen die technischen Feldnamen des Datenfeeds angegeben werden.
    Standardmäßig sind `name` (Produktname) und `descr` (Produktbeschreibung) hinterlegt.
    Änderungen an dieser Einstellung erfordern einen erneuten Import. | Die Funktion muss zusätzlich noch für das [Suchmodul](#grammatikalische-flexion-lemmatization-2) aktiviert werden. #### Kategorien **Feste Felder im Category-Index** | **Feld** | **Beschreibung** | | -------------- | ----------------------------------------------------------------------------------------------- | | `cat_id` | Kategorie-ID. | | `cat_str` | Kategorie-Name. | | `cat_id_path` | Kategorie-ID-Pfad. | | `cat_str_path` | Vollständiger Kategorie-Pfad als String. | | `cat_image` | Kategorie-Bild (optional). | | `sort_field` | Wird automatisch von `cat_str_path` befüllt und kann über `custom_fields` überschrieben werden. | #### Inhaltsseiten in den Suchindex aufnehmen Neben Produkten und gegebenenfalls Kategorien können auch statische Inhaltsseiten in die Suche einbezogen werden, beispielsweise „Über uns", AGB, Impressum oder Datenschutzerklärung. Dafür wird im **Importmodul** der Content-Import aktiviert (`content.enabled`) und die Anbindung an die jeweilige Shop-API (VX oder v8) konfiguriert. Optional lassen sich die zu indexierenden Seiten gezielt einschränken, beispielsweise über `included_content`. `Category` und `Content` sind spezielle Indizes, die, anders als der Produktindex, nicht frei um neue Felder erweitert werden können. Beide arbeiten mit einem festen Satz an Feldern, siehe unten. Der Parameter `custom_fields` dient hier ausschließlich dazu, das Elasticsearch-Mapping bestehender Felder zu überschreiben oder anzupassen, beispielsweise Analyzer oder Feldtyp. Er wurde vom Produktindex analog für andere Indizes übernommen, erweitert aber nicht die Indexierung um neue Datenfelder. **Feste Felder im Content-Index** | **Feld** | **Beschreibung** | | ------------ | ---------------------------------------------------------------------------------------- | | `source` | Pfad zur Content-Seite, beispielsweise `content/gtc.htm`. | | `title` | Seitentitel. | | `content` | Extrahierter Text-Inhalt der Seite. | | `sort_field` | Wird automatisch von `title` befüllt und kann über `custom_fields` überschrieben werden. | **Standardkonfiguration** des [Demoshops](https://demo.shop.websale.biz/) ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} content: enabled: true custom_fields: # analog zu product/category, im Default sind nur 'title' und 'content' enthalten - name: field_name type: field_type custom_config: host: demo.shop.websale.biz user: "example@websale.de" password: "" endpoint: seo/urls/templates params: size: 300 sort: resourceIdentifier:asc path_field: path source_field: resourceIdentifier content_id: "wsMainContent" included_content: - "content/aboutUs.htm" - "content/gtc.htm" - "content/imprint.htm" - "content/privacy.htm" - "content/return.htm" - "content/returnInquiry.htm" # folgende Keys sind für VX nicht relevant api_version: v8 base_path: /api/ auth_url: /authent/login/ shop_url: www.myshop.de ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `enabled` | Aktiviert den Import und das Indexieren von statischen Inhaltsseiten für die Suche. | | `custom_fields` | Optionale Anpassung des Elasticsearch-Mappings für den Content-Index, analog zu `Product` und `Category`. Damit lassen sich bestehende Felder im Mapping überschreiben oder erweitern. Verändert nur das Mapping. Die Indexierung von `Content` und `Category` ist fest definiert und lässt sich nicht über die Konfiguration um neue Datenfelder erweitern. | | `custom_config` | Technische Zusatzkonfiguration für das Importieren und Auslesen der statischen Inhalte. Unterscheidet sich zwischen VX und v8. | | `host` | Host der API.
    - **V8s:** Host der v8-API, beispielsweise `websale.de`.
    - **Neue Version:** entspricht der Shop-ID-Domain, beispielsweise `common-id.shop.websale.net`. | | `user` | Benutzername für die Authentifizierung an der Auth-API. | | `password` | Passwort für die Authentifizierung an der Auth-API. | | `endpoint` | API-Endpunkt, von dem die SEO-Template- und URL-Daten geladen werden.
    - **V8s:** `seo/templates`
    - **Neue Version:** `seo/urls/templates` | | `encoding` | Zeichencodierung der abgerufenen Inhalte, beispielsweise `utf-8`. | | `params` | Optionale URL-Parameter für den API-Call. Nur für die **neue Version**.
    - `size` — maximale Response-Größe, maximal 300 SEO-URLs pro Request.
    - `sort` — Sortierung der Response-Items, beispielsweise `resourceIdentifier:asc`. | | `osbcommonid` | **Nur für V8s.** Common-ID für OSB, sofern für die jeweilige Umgebung erforderlich. | | `path_field` | Feldname aus der API-Response, das den Pfad der Seite enthält, beispielsweise `/ueber-uns`.
    - **V8s:** `terms`
    - **Neue Version:** `path` | | `source_field` | Feldname aus der API-Response, das die Quelle beziehungsweise Template-Referenz enthält, beispielsweise `content/aboutUs.htm`.
    - **V8s:** `template`
    - **Neue Version:** `resourceIdentifier` | | `content_id` | Optionale ID eines HTML-Containers, aus dem der relevante Seiteninhalt extrahiert wird, beispielsweise `wsMainContent`.
    Wenn nicht gesetzt, wird standardmäßig `
    ` ausgelesen. Ist kein `
    ` vorhanden, wird die komplette Seite inklusive Header und Footer übernommen. | | `included_content` | Optionale Positivliste. Importiert und indexiert nur die hier angegebenen „source"-Einträge, beispielsweise einzelne Templates oder Content-Dateien.
    Ohne Angabe werden alle verfügbaren Seiten berücksichtigt. | | `api_version` | **Nur V8s.**
    Version der Shop-API, beispielsweise `v8`.
    In der neuen Version entfällt dieser Parameter, da ein passender Default-Wert hinterlegt ist. | | `base_path` | **Nur V8s.**
    Basispfad für Schnittstellen, beispielsweise `/api/`.
    In der neuen Version entfällt dieser Parameter, da ein passender Default-Wert hinterlegt ist. | | `auth_url` | **Nur V8s.**
    Endpunkt der Auth-API, beispielsweise `/authent/login/` beziehungsweise mit Common-ID.
    In der neuen Version entfällt dieser Parameter, da ein passender Default-Wert hinterlegt ist. | | `shop_url` | **Nur V8s.**
    Öffentliche Shop-URL.
    In der neuen Version entspricht `host` in der Regel der Shop-URL beziehungsweise ist dafür ausreichend. | #### Mehrere Content-Quellen für die Suche Mehrere Content-Quellen stehen ab den Plugin-Versionen **elasticsearch\_manager v1.15.0** und **websale\_search v1.18.0** zur Verfügung. Für die Darstellung einzelner Quellen im Frontend wird zusätzlich **websale\_search\_webcomponents v1.7.0** benötigt. Der im vorherigen Abschnitt beschriebene `content`-Block deckt eine einzelne Quelle ab, nämlich die statischen Inhaltsseiten des Shops. Reicht das nicht aus, lässt sich `content` stattdessen als **Liste** angeben. Jeder Eintrag der Liste ist eine eigene Content-Quelle mit eigenem Suchindex, beispielsweise die statischen Seiten, ein Blog und ein Magazin. Neben der Shop-API als Datenquelle kommt damit ein zweiter Weg hinzu. Über `source: feed` liest das Importmodul Inhalte aus einem externen Datenfeed ein, beispielsweise aus dem CSV-Export eines Blog-Systems. Die bisherige Konfiguration mit einem einzelnen `content`-Block funktioniert unverändert weiter. Sie müssen nur dann auf die Listenform umstellen, wenn Sie mehr als eine Content-Quelle benötigen. **Beispielkonfiguration mit drei Quellen** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} index_configs: content: - name: static enabled: true source: api custom_fields: # analog zu product/category, im Default sind nur 'title' und 'content' enthalten - name: field_name type: field_type custom_config: host: demo.shop.websale.biz user: "example@websale.de" password: "" endpoint: seo/urls/templates encoding: utf-8 params: size: 300 sort: resourceIdentifier:asc path_field: path source_field: resourceIdentifier content_id: "wsMainContent" included_content: - "content/aboutUs.htm" - "content/gtc.htm" - "content/imprint.htm" - name: blog enabled: true source: feed custom_fields: # optional, im Default sind nur 'title' und 'content' enthalten - name: field_name type: field_type custom_config: datafeed_url: https://blog.example.de/searchfeeds_csv/blog_DE.csv field_mapping: source: url title: title content: content_text format_config: format: csv field_separator: "," - name: magazin enabled: true source: feed custom_config: datafeed_url: https://magazin.example.de/searchfeeds_csv/magazin_DE.csv field_mapping: source: url title: h1 content: texts format_config: format: csv field_separator: "," ``` **Parameterbeschreibung** Die folgende Tabelle beschreibt nur die Parameter, die in der Listenform zusätzlich gelten. Alle übrigen Keys entsprechen dem [Content-Import über die Shop-API](#inhaltsseiten-in-den-suchindex-aufnehmen). | **Parameter** | **Beschreibung** | | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | **Pflichtfeld.** Technischer Name der Quelle. Er wird als Suffix an den Index-Namen angehängt, aus `name: blog` wird der Index `content_blog`. Der Name muss eindeutig sein. Erlaubt sind Kleinbuchstaben, Ziffern, Unterstrich und Bindestrich. Großbuchstaben werden automatisch in Kleinbuchstaben umgewandelt, alle anderen Zeichen wie Umlaute, Leerzeichen oder Punkte werden durch einen Unterstrich ersetzt. Ein Eintrag ohne `name` wird beim Import übersprungen. | | `source` | Herkunft der Inhalte.
    - `api` — die Inhalte werden über die Shop-API geladen, wie beim bisherigen Content-Import.
    - `feed` — die Inhalte werden aus einem externen Datenfeed gelesen. | | `custom_fields` | Optionale Anpassung des Elasticsearch-Mappings, analog zu `product` und `category`. Wird pro Quelle einzeln angegeben. Im Default sind nur `title` und `content` enthalten. | | `encoding` | Zeichencodierung, nur innerhalb von `custom_config` bei `source: api`, beispielsweise `utf-8`. | | `datafeed_url` | **Nur bei** `source: feed`. URL des Datenfeeds, aus dem die Inhalte gelesen werden. | | `format_config` | **Nur bei** `source: feed`. Format des Datenfeeds, analog zu `datafeed.format_config` des Produktfeeds. | | `format` | Dateiformat des Feeds. Unterstützt werden `csv`, `tsv` und `json`. | | `field_separator` | Trennzeichen zwischen den Spalten, beispielsweise `,` bei einer kommaseparierten CSV-Datei. | | `field_mapping` | **Nur bei** `source: feed`. Zuordnung der Feldnamen des Datenfeeds auf die drei festen Index-Felder. Ohne Angabe sucht das Importmodul im Feed direkt nach Spalten mit den Namen `source`, `title` und `content`. | | `source` | Feld im Feed, das die URL der Seite enthält. Default: `source` | | `title` | Feld im Feed, das den Titel enthält. Default: `title` | | `content` | Feld im Feed, das den Inhalt enthält. Default: `content` | Zusätzliche `custom_fields` lassen sich über `field_mapping` ebenfalls auf Feed-Spalten mappen. **Namen der Indizes** Aus jedem Listeneintrag entsteht ein eigener Index. Der Index-Typ heißt `content_`, der eigentliche Index-Name setzt sich aus dem Basis-Namen des Content-Index, dem Namen der Quelle und der Subshop-ID zusammen. Bei Subshop `deutsch` und `name: blog` entsteht daraus der Index `deutsch_content_blog`. Diese Namen brauchen Sie an zwei Stellen wieder, nämlich in der [Konfiguration des Suchmoduls](#inhaltsseiten-content-index) und im `source`-Attribut der WebComponents. Ist `content` weder ein einzelner Block noch eine Liste, wird die **komplette Content-Suche deaktiviert**. Es erscheint lediglich ein Log-Eintrag, aber keine Fehlermeldung im Shop. Prüfen Sie die Einrückung der Listeneinträge daher genau. *** ## Konfiguration des Suchmoduls ### Suchvorschläge (suggest\_config) **Basiskonfiguration** `suggest_config` ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} suggest_config: query: enabled: true fuzziness: 0 size: 10 product: enabled: true size: 8 category: enabled: true size: 5 content: enabled: true size: 5 ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `query` | Konfiguration für textbasierte Suchvorschläge, also die Autovervollständigung der Sucheingabe. | | `product` | Konfiguration für Produkt-Vorschläge. Grundlage bildet der Produkt-Index, siehe Import-Konfiguration. | | `category` | Konfiguration für Kategorie-Vorschläge. Grundlage bildet der Kategorie-Index, siehe Import-Konfiguration. | | `content` | Konfiguration für Inhaltsseiten-Vorschläge. Grundlage bildet der Content-Index, siehe Import-Konfiguration. | | `enabled` | Aktiviert (`true`) oder deaktiviert (`false`) den jeweiligen Suggest-Typ. Deaktivierte Typen werden im Frontend nicht angezeigt, auch wenn die entsprechenden HTML-Komponenten vorhanden sind. | | `size` | Anzahl der Suchvorschläge für den jeweiligen Suggest-Typ. | | `fuzziness` | Steuert die fehlertolerante Suchmethode, nur für Typ `query`. Sie gleicht Tippfehler oder Abweichungen in der Schreibweise innerhalb der Suggest aus.
    Es kann die erlaubte Edit-Distanz innerhalb der Suggest (Ersetzen, Einfügen, Löschen) pro Wort konfiguriert werden:
    - `0` → **keine** Fehlertoleranz, es muss nach Analyse und Normalisierung exakt passen.
    - `1` → bis zu **1** Edit erlaubt.
    - `2` → bis zu **2** Edits erlaubt.
    - `AUTO` → passt die Distanz an die Wortlänge an. Wortlänge 1 bis 2 → 0, 3 bis 5 → 1, ab 6 → 2.
    - `AUTO:x,y` → eigene Schwellen. Bis x-1 Zeichen → 0, ab x bis y-1 → 1, ab y → 2. Beispiel `AUTO:4,8`: Längen bis 4 → 0, 5 bis 8 → 1, ab 9 → 2. | Grundlage der Suggest-Typen `product`, `category` und `content` bilden die jeweiligen Indizes. Diese müssen zunächst im Importmodul aktiviert und konfiguriert sein, damit die entsprechenden Vorschläge zur Laufzeit verfügbar sind. Siehe [Kategorien](#kategorien), [Inhaltsseiten](#inhaltsseiten-in-den-suchindex-aufnehmen) sowie den [Completion-Index](#subshopkonfiguration-im-importmodul). **Suchvorschläge bei mehreren Content-Quellen** Nutzen Sie [mehrere Content-Quellen](#mehrere-content-quellen-für-die-suche), wird auch `content` im `suggest_config` zu einer Liste. Jede Quelle erhält einen eigenen Eintrag, dessen `name` mit dem Namen im Importmodul übereinstimmen muss. ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} suggest_config: query: enabled: true fuzziness: 0 size: 10 product: enabled: true size: 8 category: enabled: true size: 5 content: - name: static enabled: true size: 4 - name: blog enabled: true size: 4 - name: magazin enabled: true size: 4 ``` Quellen, die Sie hier weglassen, liefern keine Suchvorschläge. Sie erscheinen aber weiterhin in den Suchergebnissen. ### Filter (filter\_config) **Basiskonfiguration** `filter_config` ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} filter_config: filter_size: 100 doc_count: 1 default_min: 0 default_max: 1000 ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | --------------------------------------------------------------------------------------------------------- | | `filter_size` | Anzahl der Filteroptionen pro Filter. | | `doc_count` | Mindestanzahl der Dokumente, in denen ein Wert vorkommen muss, um als Filteroption zur Auswahl zu stehen. | | `default_min` | Fallback für Range-Filter, Minimalwert. | | `default_max` | Fallback für Range-Filter, Maximalwert. | ### Subshopkonfiguration für das Suchmodul Die Konfiguration des Suchmoduls ist pro Subshop definiert und wird jeweils unter der Subshop-ID als Schlüssel abgelegt. **Übersichtsbeispiel** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} subshop_configs: {subshop_id}: # beispielsweise 01-aa: oder 83-it: (lowercase) search_config: # Basiskonfiguration der Sucharten (exakt, Präfix, Fuzzy) {...} fields_config: # Felddefinitionen und Gewichtungen {...} index_configs: # Indexeinstellungen {...} punctuation_filter: # Behandlung von Sonderzeichen {...} fuzzy_filter: # Schwellenwerte für unscharfe Suche {...} stopwords_filter: # Zu ignorierende Wörter {...} lemmatization: # Wortgrundformreduktion {...} ``` ### Basiskonfiguration des Suchmoduls (search\_config) Die Basiskonfiguration definiert, welche Sucharten aktiv sind und wie Suchbegriffe ausgewertet werden. Über diese Einstellungen wird gesteuert, ob Suchbegriffe exakt, teilweise, unscharf oder als Wortbestandteile gefunden werden sollen. Jede Suchart kann separat aktiviert, gewichtet und kombiniert werden. **Grundstruktur** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} search_config: mode: add exact: {...} prefix: {...} wildcard: {...} ngram: {...} fuzzy: {...} ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `mode` | Legt fest, wie die Feldboosts der einzelnen Sucharten verrechnet werden, additiv oder multiplikativ. | | `exact` | Konfiguration für exakte Übereinstimmungen von Suchbegriffen, siehe Abschnitt [Exact Search](#exakte-suche-exact). | | `prefix` | Konfiguration für Präfix-Suchen, bei denen der Suchbegriff am Wortanfang steht, siehe Abschnitt [Prefix Search](#präfix-suche-prefix). | | `wildcard` | Konfiguration für Wildcard-Suchen, bei denen der Suchbegriff an beliebiger Stelle im Wort vorkommen kann, siehe Abschnitt [Wildcard Search](#wildcard-suche-wildcard). | | `ngram` | Konfiguration für N-Gram-Suchen, bei denen Teile des Suchbegriffs innerhalb eines Wortes übereinstimmen, siehe Abschnitt [Ngram Search](#teilwortsuche-n-gram-suche-ngram). | | `fuzzy` | Konfiguration für fehlertolerante (unscharfe) Suchen, die auch leicht abweichende Schreibweisen berücksichtigen, siehe Abschnitt [Fuzzy Search](#fehlertolerante-suche-levenshtein-distanz-fuzzy). | #### Exakte Suche (exact) Die exakte Suche liefert Treffer nur dann, wenn der Suchbegriff exakt mit dem gespeicherten Wort übereinstimmt. Sie bildet damit die präziseste Form der Suche und wird meist als Basis oder Ergänzung zu anderen Sucharten verwendet. Treffer aus der exakten Suche erhalten in der Regel eine höhere Relevanz, da sie eine vollständige Übereinstimmung darstellen. Diese Suchart sollte immer aktiviert bleiben, da sie sicherstellt, dass bei identischen Schreibweisen die relevantesten Ergebnisse zuerst erscheinen, beispielsweise bei exakten Produktnamen, Marken oder Artikelnummern. Über den *Boost-Wert* lässt sich die Gewichtung gegenüber anderen Sucharten feinjustieren. **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} exact: enabled: true boost: 2.0 tie_breaker: 0.3 ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | Aktiviert (`true`) oder deaktiviert (`false`) die exakte Suche. Sollte in der Regel aktiviert bleiben. | | `boost` | Relevanzfaktor für exakte Treffer. Ein höherer Wert verstärkt die Gewichtung exakter Übereinstimmungen im Gesamtranking. Empfohlen: 2.0 bis 3.0. | | `tie_breaker` | Bestimmt, wie stark sich Mehrfachtreffer desselben Suchbegriffs in mehreren Feldern auf den Score auswirken.
    Ein Wert von 0.1 bis 0.3 ist in der Regel sinnvoll, um die Relevanz leicht zu erhöhen, ohne sie zu dominieren. | #### Präfix-Suche (prefix) Die Präfix-Suche liefert Treffer, wenn der Suchbegriff am Anfang eines Wortes steht. Sie wird typischerweise genutzt, um Treffer während der Eingabe zu ermöglichen oder um Wortanfänge zu erkennen. Die Eingabe „schn" liefert beispielsweise auch Ergebnisse wie *Schneider*, *Schnürsenkel* oder *Schnalle*. Diese Suchart ergänzt die exakte Suche sinnvoll, da sie flexibler auf Teilbegriffe reagiert, ohne die Präzision vollständig aufzugeben. Besonders nützlich ist sie in Kombination mit Autocomplete-Funktionen und Suggest-Komponenten. **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} prefix: enabled: true boost: 1.75 ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | Aktiviert (`true`) oder deaktiviert (`false`) die Präfix-Suche. | | `boost` | Relevanzfaktor für Präfix-Treffer.
    Empfohlener Bereich: 1.0 bis 2.0, um Wortanfänge leicht zu bevorzugen, ohne exakte Treffer zu verdrängen. | #### Wildcard-Suche (wildcard) Die Wildcard-Suche findet Treffer, wenn der Suchbegriff an beliebiger Stelle innerhalb eines Wortes vorkommt. Sie ist deutlich flexibler als die Präfix-Suche, da sie auch Wortbestandteile erkennt. Die Eingabe „hose" liefert beispielsweise Treffer wie *Jeanshose*, *Arbeitshose* oder *Strumpfhose*. Diese Suchart eignet sich besonders für Fälle, in denen Nutzer nicht den exakten Wortanfang kennen, beispielsweise bei zusammengesetzten Begriffen, Varianten von Produktnamen oder technischen Bezeichnungen. **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} wildcard: enabled: true boost: 1.5 ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | Aktiviert (`true`) oder deaktiviert (`false`) die Wildcard-Suche. Empfohlen, wenn Teilbegriffe oder Wortbestandteile relevant sind. | | `boost` | Relevanzfaktor für Wildcard-Treffer.
    Empfohlener Bereich: 0.5 bis 1.5, um flexible Treffer zuzulassen, aber exakte Übereinstimmungen weiterhin zu priorisieren. | #### Teilwortsuche / N-Gram-Suche (ngram) Die N-Gram-Suche ermöglicht Treffer, wenn ein Teil des Suchbegriffs innerhalb eines Wortes vorkommt, unabhängig davon, ob der Begriff am Anfang, in der Mitte oder am Ende steht. Sie basiert auf der Aufteilung von Wörtern in kleine Einheiten, die sogenannten *N-Gramme*, die während des Indexaufbaus erzeugt werden. Diese Suchart eignet sich besonders für technische Begriffe, Modellnummern, Artikelcodes oder zusammengesetzte Wörter, bei denen der Nutzer häufig nur Teile des Begriffs kennt. Die Eingabe „AB12" findet beispielsweise auch *AB1234-X* oder *XX-AB12-Z*. **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ngram: enabled: true boost: 1.25 tie_breaker: 0.3 minimum_should_match: 80% ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | Aktiviert (`true`) oder deaktiviert (`false`) die N-Gram-Suche. | | `boost` | Relevanzfaktor für Teilworttreffer.
    Empfohlener Bereich: 0.8 bis 1.5, um ergänzende Treffer zuzulassen, ohne exakte Ergebnisse zu verdrängen. | | `tie_breaker` | Bestimmt, wie stark Mehrfachtreffer in verschiedenen Feldern den Gesamtscore beeinflussen.
    Werte zwischen 0.1 und 0.3 sind in der Regel sinnvoll. | | `minimum_should_match` | Über den Parameter kann gesteuert werden, wie viel Prozent der N-Gramme übereinstimmen müssen, um als Treffer zu zählen. Das verbessert die Ergebnisqualität.
    Empfohlen: 60 bis 80 % für eine gute Balance zwischen Trefferquote und Präzision. | #### Fehlertolerante Suche & Levenshtein-Distanz (fuzzy) Die Fuzzy-Suche ist eine fehlertolerante Suchmethode, die Tippfehler oder Abweichungen in der Schreibweise ausgleicht. Grundlage ist die Levenshtein-Distanz, die zählt, wie viele Bearbeitungsschritte (Einfügen, Löschen, Ersetzen) zwei Wörter voneinander trennen. Beispiele: * „Haus" → „Maus" = Distanz 1 (1 Buchstabe ersetzt) * „Haus" → „Huas" = Distanz 2 (Buchstaben vertauscht, also zweimal ersetzt) * „Haus" → „Hause" = Distanz 1 (ein Buchstabe eingefügt) `fuzzy` steuert die globale fehlertolerante Suche auf Basis der Levenshtein-Distanz. Hier wird festgelegt, ob Fuzzy aktiv ist, welche Fehlertoleranz gilt, beispielsweise `AUTO` abhängig von der Wortlänge, und wie stark fuzzy Treffer im Scoring gewichtet werden (`boost`, `tie_breaker`). Die Konfiguration wirkt grundsätzlich auf alle Suchbegriffe und Felder, sofern sie nicht durch nachgelagerte Regeln eingeschränkt wird. Siehe [Ausnahmen zur globalen Fuzzy-Logik (fuzzy\_filter)](#ausnahmen-zur-globalen-fuzzy-logik-fuzzy_filter). **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ... fuzzy: enabled: true boost: 0.75 tie_breaker: 0.3 fuzziness: AUTO ... ``` * **Fuzzy-Suche aktiviert:** Fehlertolerante Matches auf Basis der Levenshtein-Distanz sind aktiv. * **Gewichtung:** Mit `boost = 0.75` erhalten fuzzy-Treffer rund 75 % des Gewichts eines exakten Treffers. Höhere Werte priorisieren fuzzy stärker, `0` deaktiviert den Boost-Effekt. * **Feldübergreifende Gewichtung:** `tie_breaker = 0.3` bewirkt, dass zusätzliche Treffer in weiteren Feldern den Score mit etwa 30 % beitragen. Kleinere Werte dämpfen diesen Mehrfeld-Effekt, größere verstärken ihn. * **Fehlertoleranz:** `fuzziness = AUTO` passt die erlaubte Edit-Distanz an die Wortlänge an. 1 bis 2 Zeichen → 0, 3 bis 5 → 1, ab 6 → 2. **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | Aktiviert oder deaktiviert die fehlertolerante Suche. Bei `false` findet **keine** Fuzzy-Auswertung statt. Einstellungen wie `fuzziness`, `boost` oder `tie_breaker` greifen dann nicht. | | `boost` | Gewichtet den Einfluss der Fuzzy-Treffer im Ranking.
    - `1.0` entspricht neutral, also weder Ab- noch Aufwertung.
    - Werte `< 1.0` schwächen Fuzzy gegenüber exakten Treffern ab, beispielsweise `0.75`.
    - Werte `> 1.0` stärken Fuzzy, beispielsweise `1.5`.
    - `0` bedeutet, dass Fuzzy-Treffer das Scoring nicht beeinflussen. Die Abfrage kann weiterhin matchen, liefert aber keinen Score-Beitrag. | | `fuzziness` | Steuert die erlaubte Edit-Distanz (Ersetzen, Einfügen, Löschen) pro Wort.
    - `0` → **keine** Fehlertoleranz, es muss nach Analyse und Normalisierung exakt passen.
    - `1` → bis zu **1** Edit erlaubt.
    - `2` → bis zu **2** Edits erlaubt.
    - `AUTO` → passt die Distanz an die Wortlänge an. Wortlänge 1 bis 2 → 0, 3 bis 5 → 1, ab 6 → 2.
    - `AUTO:x,y` → eigene Schwellen. Bis x-1 Zeichen → 0, ab x bis y-1 → 1, ab y → 2. Beispiel `AUTO:4,8`: Längen bis 4 → 0, 5 bis 8 → 1, ab 9 → 2. | | `tie_breaker` | Bei einer Suche wird meist in mehreren Feldern gleichzeitig gesucht, etwa im Titel, in der Marke und in der Beschreibung. Das System bewertet jedes Feld separat. Zuerst zählt immer das Feld mit der besten Übereinstimmung, beispielsweise der Titel.
    `tie_breaker` legt fest, wie stark zusätzliche Treffer in den anderen Feldern den Gesamtscore mittragen.
    - Mit `tie_breaker = 0.0` zählt **nur** das beste Feld. Treffer in weiteren Feldern bringen **keinen** Zusatzpunkt.
    - Mit einem **moderaten Wert** von etwa **0.2 bis 0.4** liefern die anderen Felder **einen kleinen Bonus**. Treffer in mehreren Feldern werden also sichtbar, ohne das Ranking zu dominieren.
    - Mit **1.0** würden **alle Felder voll** addiert. Das ist selten sinnvoll, weil schwächere Treffer aus langen Beschreibungen sonst zu viel Gewicht bekommen.
    **Beispiel:** Ein Begriff passt sehr gut im Titel (Score 10), mittel in Marke (6) und schwach in Beschreibung (3).
    - **0.0** → Gesamtscore etwa **10**, nur der Titel zählt.
    - **0.3** → Gesamtscore etwa **10 + 0.3×(6+3) = 12.7**. Der Titel bleibt führend, die anderen Felder helfen ein wenig. | ### Datenfelder Mit `fields_config` wird festgelegt, welche Datenfelder in den Suchindex aufgenommen werden und wofür sie genutzt werden, also Suche, Anzeige, Filter, Sortierung, Teilwortsuche, Varianten und Kategorien. Änderungen an diesem Block werden nach Neustart des Suchmoduls aktiv. **Grundstruktur** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} fields_config: search_fields: - {...} - {...} display_fields: - {...} - {...} filter_fields: {...} sort_fields: - {...} - {...} ngram_fields: - "..." - "..." variant_fields: - "..." - "..." category_field: "" ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `search_fields` | Definition der Felder, in denen gesucht werden soll, siehe Abschnitt [Search Fields](#datenfelder-für-die-suche-search_fields). | | `display_fields` | Angabe der Felder, die im Suchergebnis an das Frontend übergeben werden, siehe Abschnitt [Display Fields](#datenfelder-im-such-response-display_fields). | | `filter_fields` | Definition der verfügbaren Filter und deren Typen im Such-Frontend, siehe Abschnitt [Filter Fields](#datenfelder-für-die-filter-filter_fields). | | `sort_fields` | Angabe der Felder, nach denen die Ergebnisse sortiert werden können, siehe Abschnitt [Sort Fields](#datenfelder-für-die-sortierung-sort_fields). | | `ngram_fields` | Festlegung der Felder, für die die Teilwortsuche (N-Gram-Suche) aktiv ist, siehe Abschnitt [Ngram Fields](#datenfelder-für-teilwortsuche-ngram_fields). | | `variant_fields` | Definition der Felder, die Produktvarianten kennzeichnen, siehe Abschnitt [Variant Fields](#variantenfelder-für-filter-variant_fields). | | `category_field` | Angabe des Feldes, das die Kategorie-IDs enthält, siehe Abschnitt [Category Field](#kategoriefelder-category_field). | #### Datenfelder für die Suche (search\_fields) In diesem Abschnitt wird festgelegt, in welchen Feldern die Suche tatsächlich durchgeführt wird. Ohne definierte Suchfelder kann keine inhaltliche Suche stattfinden. Die Auswahl der Felder hängt vom jeweiligen Shop ab. Typischerweise werden Produktname, Beschreibung, Kategoriebezeichnungen, Marke oder Hersteller und Farbvarianten angegeben. **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} fields_config: ... search_fields: - field: name boost: 3 - field: descr boost: 2 - field: brand boost: 1.5 ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `field` | Name des Datenfeldes, das in den Suchindex aufgenommen und somit auch durchsucht werden soll.
    Es muss der technische Feldname des Datenfelds aus dem Datenfeed angegeben werden, das diese Information enthält, beispielsweise
    - Produktname (`name`)
    - Produktbeschreibung (`descr`)
    - Marke (`brand`) | | `boost` | Optionaler Relevanzfaktor für das angegebene Datenfeld.
    Die Relevanzwerte reichen von 1 (niedrig) bis 5 (hoch). Höhere Werte bedeuten, dass das Feld bei der Berechnung des Suchergebnisses stärker gewichtet wird. | #### Datenfelder im Such-Response (display\_fields) In diesem Abschnitt wird festgelegt, welche Felder im Such-Response an das Shop-Frontend übergeben werden. Diese Felder können anschließend direkt in den WebComponents zur Anzeige verwendet werden. Standardmäßig wird nur die Produktnummer beziehungsweise der Produktindex zurückgegeben, da im Standard über diesen Index die Produktdaten aus der Shopdatenbank geladen und durch die WEBSALE Template-Engine im Frontend dargestellt werden. Wenn die Darstellung der Produkte nicht über das Laden der Shopdatenbank und somit nicht über die WEBSALE Template-Engine erfolgen soll, müssen in diesem Abschnitt alle Felder ergänzt werden, die für die Anzeige im Frontend benötigt werden, beispielsweise Preis, Marke oder Produktbild. Weitere Informationen siehe [Integration in die Templates (Storefront)](/ws-search/integration-in-die-templates-storefront). **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} fields_config: ... display_fields: - field: baseprodindex - field: prodindexbase ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | ----------------------------------------------------------------------------------------- | | `field` | Es muss der technische Feldname des Produktdatenfelds aus dem Datenfeed angegeben werden. | #### Datenfelder für die Filter (filter\_fields) In diesem Abschnitt wird festgelegt, welche Filter im Such-Frontend verfügbar sind und nach welchen Feldwerten gefiltert werden kann. Das Filtersystem unterstützt verschiedene Typen von Filtern, die direkt über die Konfiguration definiert werden. Je nach Datentyp oder Anwendungsfall können so einfache Auswahlfilter, Preisbereiche oder benutzerdefinierte Filterlogiken erstellt werden. Unterstützte Filtertypen: * **Terms-Filter (`terms`)**: exakte Werte, beispielsweise Marken, Farben oder Kategorien. * **Range-Filter (`range`)**: numerische Wertebereiche, beispielsweise Preis oder Bewertung. * **Custom-Filter (`custom`)**: benutzerdefinierte Bedingungen, beispielsweise „salesrank ≤ 1000". * **Default-Filter (`default`)**: automatisch aktive Filter, beispielsweise „nur verfügbare Produkte". **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} fields_config: ... filter_fields: farbgrp: type: terms label: Farbe price: type: range label: Preis salesrank: type: custom label: Bestseller op_type: lte filter_value: 1000 rating: type: custom label: Top bewertet op_type: gte filter_value: 4.0 new_field: type: custom label: NEU op_type: eq filter_value: true inventory: # wird dauerhaft und nicht sichtbar angewendet, sorgt dafür, # dass die Suche wirklich nur verfügbare Produkte anzeigt - type: default op_type: gt filter_value: 0 # damit der Kunde entscheiden kann, dass er auch nicht verfügbare # Produkte angezeigt bekommt - type: custom label: "Nicht verfügbare Artikel" op_type: rm ``` * **Terms-Filter** `farbgrp` für Farben. * **Range-Filter** `price` für den Preis von und bis. * **Custom-Filter** `salesrank`, der Produkte mit einem Verkaufsrang kleiner oder gleich 1000 filtert. * **Custom-Filter** `rating`, der Produkte mit einer durchschnittlichen Kundenbewertung größer oder gleich 4 filtert. * **Custom-Filter** `new_field`, der Produkte filtert, die mit Neu gekennzeichnet sind. * **Default-Filter** `inventory`, der standardmäßig alle nicht verfügbaren Produkte ausfiltert, kombiniert mit einem Custom-Filter, der es ermöglicht, diesen Default-Filter zu entfernen und damit auch nicht verfügbare Produkte anzuzeigen. **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `` | Technischer Feldname des Datenfelds aus dem Datenfeed, auf das sich der Filter bezieht, beispielsweise:
    - Farbe → `farbgrp`
    - Preis → `price`
    - Verkaufsrang → `salesrank`
    - Lagerbestand → `inventory`
    Werden mehrere Filter auf dasselbe Feld angewendet, muss eine **Liste** konfiguriert werden. Jeder Listeneintrag beginnt mit einem Bindestrich (`-`). Ein Beispiel dafür ist die Filterdefinition für `inventory` mit einem Default- und einem Custom-Filter, siehe oben im Codebeispiel für die Standardkonfiguration. | | `type` | Typ des Filters: `terms`, `range`, `custom` oder `default`.
    Neben kundenspezifischen (dynamischen) Filtern stehen im Standard bereits vordefinierte `custom`- und `default`-Filter zur Verfügung, beispielsweise salesrank, rating, new\_field oder inventory. | | `label` | Optionaler Anzeigename des Filters, der im Frontend dargestellt wird. | | `op_type` | Bedingungstyp für benutzerdefinierte Filter. Legt fest, wie der Vergleich des Feldwerts erfolgen soll.
    Verfügbare Operatoren:
    - `eq` — *equal* → gleich
    - `lt` — *less than* → kleiner als
    - `lte` — *less than or equal* → kleiner oder gleich
    - `gt` — *greater than* → größer als
    - `gte` — *greater than or equal* → größer oder gleich
    - `rm` — *remove* → entfernt einen zuvor gesetzten Filter, beispielsweise zur Aufhebung eines Default-Filters
    Nur für Filter des `type: custom` und `type: default` relevant. | | `filter_value` | Vergleichswert, mit dem die Filterbedingung geprüft wird. Wird zusammen mit `op_type` verwendet, um festzulegen, welche Produkte ein- oder ausgeschlossen werden.
    Beispiele:
    - `0` bei `inventory` → zeigt nur Produkte mit einem Lagerbestand größer 0.
    - `true` bei `new_field` → zeigt nur Produkte, die als **„neu"** gekennzeichnet sind.
    Nur relevant für Filter des Typs `custom` und `default`.
    Über `filter_value` können auch [Produkte ausgeschlossen werden](#ausschluss-bestimmter-produkte-filter_fields). | #### Ausschluss bestimmter Produkte (filter\_fields) Standardmäßig erscheinen alle aktiven Produkte in der Suche. Der Ausschluss bestimmter Produkte erfolgt innerhalb von [filter\_fields](#datenfelder-für-die-filter-filter_fields). Über `filter_fields` können Produkte regelbasiert ausgeschlossen werden, ohne sie offline zu nehmen. Dieser Abschnitt beschreibt die Konfiguration im Suchmodul. Aktive Regeln filtern die betroffenen Artikel zur Laufzeit aus den Suchergebnissen. **Beispielkonfiguration** `filter_fields` ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} filter_fields: # Ausschluss: Produktnummer enthält "99", "88" ODER "77" produktnummer: type: default op_type: neq filter_value: - "99*" - "*88" - "*77*" # Ausschluss: Kategorie ist "Sonderposten" ODER "Testkategorie" category: type: default op_type: neq filter_value: - "Sonderposten" - "Testkategorie" # Ausschluss: Marke ist "adidas" und beispielsweise auch "adidas originals" ODER "Puma" brand: type: default op_type: neq filter_value: - "adidas*" - "Puma" # Ausschluss: Reduziert/SALE ist "true", das Produkt ist also im SALE beziehungsweise reduziert is_reduced: type: default op_type: eq filter_value: true ``` **Parameterbeschreibung** `filter_fields` Jeder Eintrag unter `filter_fields` ist eine Regel pro Datenfeld. Diese Regel wird bei jeder Suche geprüft und entscheidet, ob ein Produkt in die Ergebnisliste darf oder nicht. | **Parameter** | **Beschreibung** | | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `filter_value` | Vergleichswerte der Regel. Es wird definiert, **wogegen** verglichen wird.
    Mehrere Felder unter `filter_fields` werden **UND** verknüpft, alle Regeln müssen also erfüllt sein.
    Mögliche Eingaben und Werte beziehen sich auf den Datentyp des Datenfeldes im Suchindex:
    - Datentyp `Text`: Unterstützt Text und `*`-Wildcards. `TEST*` beginnt mit TEST, `*TEST` endet mit TEST, `*TEST*` enthält TEST. Mehrere Werte können als Array angegeben werden, innerhalb des Feldes gilt ODER-Logik.
    - Datentyp `Bool/Zahl`: ohne Wildcards, exakt angeben, beispielsweise `true`/`false` oder `0`/`1`. | Mehr Informationen zu den filter\_fields sowie eine vollständige Übersicht der Parameter finden Sie im Abschnitt [Datenfelder für die Filter (filter\_fields)](#datenfelder-für-die-filter-filter_fields). #### Datenfelder für die Sortierung (sort\_fields) Dieser Block wird nur konfiguriert, wenn die UI-Komponente `` verwendet wird. In diesem Fall liest die Komponente die Einträge aus `sort_fields` und generiert automatisch eine Select-Box mit allen konfigurierten Sortieroptionen. Änderungen an `sort_fields` sind dadurch sofort im Frontend sichtbar, ohne dass das Template angepasst werden muss. Wird `use-api="false"` genutzt, ist `sort_fields` nicht erforderlich. Die Sortier-UI wird dann manuell über das Template bereitgestellt. Mehr zur UI-Komponente ws-sort-box finden Sie [hier](/ws-search/integration-in-die-templates-storefront/webcomponents/ui-komponenten/ws-sort-box). **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} fields_config: ... sort_fields: - field: _score label: desc: Relevanz - field: name label: asc: Alphabetisch (A-Z) desc: Alphabetisch (Z-A) - field: price label: asc: Preis aufsteigend desc: Preis absteigend ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `field` | Es muss der technische Feldname des Datenfelds aus dem Datenfeed angegeben werden, das für die Sortierung verwendet werden soll. | | `label` | Definition der im Frontend angezeigten Sortierbezeichnungen. Wenn kein Label angegeben ist, wird die Sortierung nicht erstellt. | | `asc` | Anzeigename der aufsteigenden Sortierung, beispielsweise Preis aufsteigend. | | `desc` | Anzeigename der absteigenden Sortierung, beispielsweise Preis absteigend. | #### Datenfelder für Teilwortsuche (ngram\_fields) In diesem Abschnitt wird festgelegt, für welche Felder die Teilwortsuche (N-Gram-Suche) aktiviert wird. Die Teilwortsuche ermöglicht es, auch bei unvollständigen oder teilweise passenden Suchanfragen Treffer zu finden. Die Eingabe „jack" liefert beispielsweise auch Ergebnisse wie Jacke, Jacket oder Jackett. Beim Aufbau des Suchindex werden für die hier definierten Felder sogenannte N-Gram-Token erzeugt. Dadurch können Suchbegriffe bereits während der Eingabe oder bei ungenauer Schreibweise erkannt werden. Typische Felder sind Produktname, Beschreibung oder Artikelnummern. **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} fields_config: ... ngram_fields: - name - descr - number ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | -------------- | ------------------------------------------------------------------------------------------------------------------ | | `ngram_fields` | Liste der technischen Feldnamen des Datenfelds aus dem Datenfeed, für die die Teilwortsuche aktiviert werden soll. | #### Variantenfelder für Filter (variant\_fields) In diesem Abschnitt wird festgelegt, welche Variantenattribute bei der Ermittlung von Filterwerten berücksichtigt werden sollen. Da die Berechnung von Filteroptionen (Aggregation) über viele Variantenprodukte performancekritisch ist, müssen die relevanten Variantenfelder hier explizit angegeben werden. Nur die in diesem Abschnitt definierten Felder fließen bei der Filterermittlung ein und beziehen dabei die Varianten eines Produkts mit ein. **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} fields_config: ... variant_fields: enabled: true fields: - size - color ``` * In diesem Beispiel werden die Felder **Farbe** (`color`) und **Größe** (`size`) als Variantenfelder definiert. **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------- | | `enabled` | Aktiviert die Berücksichtigung von Variantenattributen aus dem Datenfeed, um diese als Filterwerte bereitzustellen. | | `fields` | Liste der technischen Feldnamen von Variantenattributen. | #### Kategoriefelder (category\_field) In diesem Abschnitt wird der Feldname eingetragen, der die Kategorie-IDs (Kategorieindizes) enthält. Der hier konfigurierte Feldname wird vom Suchmodul verwendet, um den Kontext korrekt zu bestimmen, also Suchergebnisseite oder Kategorieseite, und Produkte nach einer Suche, Filterung oder Sortierung in der richtigen Kategorie zu öffnen. Der Standardwert ist in der Regel bereits gesetzt und sollte nicht geändert werden. **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} fields_config: ... category_field: catids ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ---------------- | -------------------------------------------------------------------------------------------- | | `category_field` | Enthält immer den Feldnamen des Datenfelds aus dem Datenfeed, das die Kategorie-IDs enthält. | ### Ausnahmen zur globalen Fuzzy-Logik (fuzzy\_filter) `fuzzy_filter` definiert **gezielte Ausnahmen** zur globalen Fuzzy-Logik. Damit lassen sich einzelne Begriffe stets **exakt** suchen, also ohne Fuzzy, um Verwechslungen zu vermeiden. Ebenso lassen sich ganze **Felder** von Fuzzy ausschließen, beispielsweise Produkt-IDs. Dieser Abschnitt dient der Feinsteuerung, wenn das Standardverhalten zu unerwünschten Treffern führt oder bestimmte Datenfelder grundsätzlich exakt behandelt werden sollen. **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} ... fuzzy_filter: enabled: true list: [] excluded_fields: - productnumber - productid ... ``` * **Fuzzy-Suche aktiviert:** Tippfehler werden gemäß der globalen Fuzzy-Toleranz in der `search_config` toleriert, beispielsweise abhängig von der Wortlänge. * **Keine globalen Wort-Ausschlüsse:** Die Liste `list` ist absichtlich leer, da kritische Begriffe je Shop variieren und individuell gepflegt werden sollten. * **Felder ohne Fuzzy:** In `productnumber` und `productid` wird **kein** Fuzzy-Match durchgeführt, dort gilt die exakte Suche auf IDs und SKUs. **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | Aktiviert (`true`) oder deaktiviert (`false`) den Fuzzy-Filter.
    Wenn `true`, wird der Fuzzy-Filter angewendet, bestimmte Felder oder Begriffe werden also laut `excluded_fields` beziehungsweise `list` von der Fuzzy-Suche ausgeschlossen.
    Wenn `false`, ist der Fuzzy-Filter inaktiv und die Fuzzy-Suche greift auf alle Felder ohne Einschränkung zu. | | `list` | Liste von Begriffen, die ohne Fuzzy gesucht werden, also exakt.
    Diese Wörter werden exakt gesucht, auch wenn Tippfehler vorliegen. Nützlich für kritische Begriffe oder Begriffe mit hoher Verwechslungsgefahr.
    **Beispiel:**
    `list:`
    ` - westen`
    ` - western`
    Wenn hier `westen` und `western` eingetragen werden, gelten für diese beiden Wörter keine Tippfehler-Toleranzen. Dadurch werden Verwechslungen verhindert, beispielsweise zwischen der Kategorie *Western* und dem Kleidungsstück *Westen*. | | `excluded_fields` | Felder, in denen Fuzzy grundsätzlich nicht angewendet werden soll, beispielsweise `productnumber` oder `productid` für die exakte ID-Suche. | ### Sonderzeichen-Handhabung (punctuation\_filter) Der `punctuation_filter` steuert die Behandlung von Sonderzeichen in Suchanfragen und indexierten Begriffen. Damit lassen sich Suchergebnisse vereinheitlichen und Null-Treffer durch unterschiedliche Schreibweisen vermeiden, beispielsweise *USB-C*, *USB C* und *USBC*. Eine Anpassung ist erforderlich, wenn vom Standardverhalten abgewichen werden soll, etwa wenn bestimmte Sonderzeichen zusätzlich erhalten bleiben sollen wie `&` bei Markennamen, oder wenn weitere Zeichen entfernt werden müssen. **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} punctuation_filter: enabled: true # Aktivierung und Deaktivierung der Funktion replace_with_space: # Zeichen die mit einem Whitespace ersetzt werden sollen - "-" - "/" type: black # white = whitelist, black = blacklist list: # Liste von Zeichen die entfernt oder behalten werden sollen, je nach type - "_" - "&" - "." ``` * **Bindestriche (`-`)** und **Schrägstriche (`/`)** werden durch Leerzeichen ersetzt. „USB-C" entspricht damit „USB C" und „Herren/Hemd" entspricht „Herren Hemd". * **Unterstriche (`_`), kaufmännisches Und (`&`) und Punkte (`.`)** werden entfernt. „Winter\_Pullover" entspricht damit „Winter Pullover", „Jack\&Jones" entspricht „Jack Jones" und „PS.5" entspricht „PS5". * Alle anderen Zeichen bleiben erhalten. **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | Aktiviert (`true`) oder deaktiviert (`false`) die Sonderzeichen-Normalisierung. | | `replace_with_space` | Liste von Zeichen, die nicht gelöscht, sondern durch ein Leerzeichen ersetzt werden. Sinnvoll für Trennzeichen, die eine Wortgrenze markieren sollen, beispielsweise `-` oder `/`. | | `type` | Legt fest, wie die Liste interpretiert wird:
    - `black` = Blacklist → Nur die angegebenen Zeichen werden entfernt, alle anderen bleiben erhalten.
    - `white` = Whitelist → Nur die angegebenen Zeichen bleiben erhalten, alle anderen werden entfernt. | | `list` | Die konkrete Zeichenliste, die je nach `type` entfernt oder behalten wird. | ### Toleranz für das Ignorieren von Stopwörtern (stopwords\_filter) Die Konfiguration im Suchmodul legt ausschließlich fest, **ob** die beim Import definierte Stopwort-Liste während der Anfrageauswertung berücksichtigt wird. Mit `stopwords_filter` wird das Ignorieren von Stopwörtern zur Laufzeit ein- oder ausgeschaltet. Ist es aktiv, werden Begriffe aus der hinterlegten Liste vor dem Matching entfernt, während Wörter aus der Whitelist **nicht** entfernt und damit ganz normal gewertet werden. Die inhaltliche Zusammenstellung der Stopwort-Liste selbst erfolgt **nicht** im Suchmodul, sondern vollständig im [Importmodul](#toleranz-für-das-ignorieren-von-stoppwörtern-stopwords). **Standardkonfiguration** `stopwords_filter` ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} stopwords_filter: enabled: true ``` **Parameterbeschreibung** `stopwords_filter` | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | Aktiviert (`true`) oder deaktiviert (`false`) die Toleranz für das Ignorieren von Stopwörtern.
    Ist nur sinnvoll in Kombination mit einer gepflegten Stopwort-Liste aus dem Import. | ### Grammatikalische Flexion (lemmatization) In diesem Abschnitt wird festgelegt, ob und in welcher Sprache Suchbegriffe während der Suche auf ihre grammatikalische Grundform reduziert werden. Dadurch erkennt das System, dass unterschiedliche Wortformen denselben Begriff meinen, etwa „rote Hemden", „rotes Hemd" oder „Hemd in Rot". Die Funktion verbessert die semantische Erkennung und sorgt für natürlichere Suchergebnisse. Für technische Felder wie Produktnummern oder Modellcodes kann die Lemmatization deaktiviert bleiben, um exakte Zeichenfolgen zu wahren. Von der Verwendung der grammatikalischen Flexion (Lemmatisierung) zur Suchzeit wird abgeraten. Suchanfragen bestehen im E-Commerce typischerweise aus nur einem bis drei Wörtern und liefern damit nicht genügend Kontext für eine zuverlässige Lemmatisierung in deutscher Sprache. Dadurch kann die Nutzerabsicht verfälscht werden, beispielsweise wird aus „blau" fälschlich „blauen", und die Suche liefert unvorhersehbare oder fehlende Ergebnisse. In der Praxis werden die relevanten Varianten bereits durch die vorhandenen Match-Strategien abgedeckt, unter anderem Exact, Prefix, N-gram, Fuzzy und Wildcard. Falls spezielle Fälle abgebildet werden müssen, ist ein Synonym-Mapping die bessere Alternative, da es kontrollierbar und nachvollziehbar ist. Die Lemmatisierung kann weiterhin zur Index-Zeit sinnvoll sein, beispielsweise bei längeren Produkttexten mit ausreichend Kontext. Sie sollte jedoch nicht bei der Verarbeitung der Suchanfrage aktiviert werden. **Standardkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} lemmatization: enabled: true language: de ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | Aktiviert (`true`) oder deaktiviert (`false`) die grammatikalische Reduktion von Suchbegriffen auf ihre Grundform.
    Grundlage sind die sprachspezifischen Wortstämme und Modelle der NLP-Bibliotheken [*spaCy*](https://spacy.io/) und [Simplemma](https://adbar.github.io/simplemma/).
    Bei deaktivierter Einstellung erfolgt eine wortgenaue Suche ohne sprachliche Vereinheitlichung. | | `language` | Definiert die Sprache, für die der Lemmatizer angewendet wird. Aktuell verfügbar:
    - Deutsch (`de`) = Standard
    - Englisch (`en`)
    - Spanisch (`es`)
    - Französisch (`fr`)
    - Italienisch (`it`)
    - Niederländisch (`nl`)
    - Portugiesisch (`pt`)
    - Dänisch (`da`)
    - Tschechisch (`cs`)
    - Polnisch (`pl`)
    - Finnisch (`fi`)
    - Indonesisch (`id`)
    - Slowakisch (`sk`)
    - Türkisch (`tr`)
    - Schwedisch (`sv`)
    - Norwegisch Bokmål (`nb`)
    Je nach gewählter Sprache werden die entsprechenden Sprachmodelle von [*spaCy*](https://spacy.io/) und [Simplemma](https://adbar.github.io/simplemma/) genutzt, um grammatikalische Varianten korrekt zu erkennen. | ### Index-Konfiguration (index\_configs) Über `index_configs` wird pro Subshop gesteuert, welche Indizes bei der Suche zur Laufzeit aktiv sind und wie sie sich verhalten. Ein Index muss sowohl im [Importmodul](#subshopkonfiguration-im-importmodul) als auch hier im Suchmodul aktiviert sein, um wirksam zu werden. **Grundstruktur** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} index_configs: product: # Hauptindex für Produktsuche {...} completion: # Index für Autovervollständigung {...} category: # Index für Kategoriesuche {...} content: # Index für statische Inhaltsseiten {...} ``` #### Produkte (Product-Index) Der Product-Index ist der Hauptindex und bildet die Grundlage jeder Produktsuche. Er ist in der Regel immer aktiv. Die inhaltliche Konfiguration, also welche Felder durchsucht, gefiltert oder angezeigt werden, erfolgt über [fields\_config](#datenfelder). Über `index_configs.product` wird primär gesteuert, ob der Index zur Laufzeit aktiv ist. **Beispielkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} index_configs: product: enabled: true ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | Aktiviert (`true`) oder deaktiviert (`false`) den Produkt-Index im Suchmodul. Sollte in der Regel auf `true` gesetzt bleiben. Muss auch im [Importmodul](#importmodul-der-suche) aktiviert sein (`index_configs.product.enabled`). | #### Autovervollständigung (Completion-Index) Der Completion-Index wird für die Autovervollständigung von Suchbegriffen verwendet. Wie beim Product-Index beschränkt sich die Konfiguration hier auf die Aktivierung des Index. Weitergehende Einstellungen wie `fuzziness` werden über [suggest\_config](#suchvorschläge-suggest_config) gesteuert, die inhaltliche Grundlage wird beim Import festgelegt. **Beispielkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} index_configs: completion: enabled: true ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | Aktiviert (`true`) oder deaktiviert (`false`) den Completion-Index im Suchmodul. Muss auch im [Importmodul](#importmodul-der-suche) aktiviert sein (`index_configs.completion.enabled`). | #### Kategorien (Category-Index) Wenn beim Import ein Kategorie-Index angelegt wurde, kann dieser im Suchmodul pro Subshop aktiviert werden. Dadurch werden neben Produkten und gegebenenfalls Inhaltsseiten auch Kategorien in der Suche berücksichtigt. **Beispielkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} index_configs: category: enabled: true custom_config: search_fields: - field: cat_str boost: 2 - field: cat_str_path boost: 1.5 display_fields: - field: cat_id - field: cat_id_path - field: cat_str - field: cat_str_path search_config: exact: enabled: true boost: 2.0 tie_breaker: 0.3 ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | Aktiviert die Suche im Kategorie-Index für den jeweiligen Subshop. | | `custom_config` | Konfigurationsblock für die Kategoriesuche. Legt fest, welche Felder durchsucht und welche in der Antwort zurückgegeben werden. Dieser Key wird für zukünftige zusätzliche Indizes analog übernommen. | | `search_fields` | Liste der Felder, die bei einer Kategoriesuche durchsucht werden. Sollte immer mindestens `cat_str` und `cat_str_path` enthalten. Pro Feld kann ein `boost`-Wert angegeben werden. Alle untergeordneten Keys sind in [diesem Abschnitt](#datenfelder-für-die-suche-search_fields) dokumentiert. | | `display_fields` | Liste der Felder, die in der Suchantwort zurückgegeben werden. Benötigt wird mindestens `cat_id`. Alle untergeordneten Keys sind in [diesem Abschnitt](#datenfelder-im-such-response-display_fields) dokumentiert. | | `search_config` | Optionaler Konfigurationsblock zur Steuerung der Sucharten für den Kategorie-Index. Analog zur [Basiskonfiguration des Suchmoduls](#basiskonfiguration-des-suchmoduls-search_config) können die einzelnen Sucharten (`exact`, `prefix`, `wildcard`, `ngram`, `fuzzy`) gezielt aktiviert, deaktiviert und gewichtet werden. | #### Inhaltsseiten (Content-Index) Wenn beim Import ein **Content-Index** angelegt wurde, kann dieser im Suchmodul pro Subshop aktiviert werden. Dadurch werden neben Produkten und gegebenenfalls Kategorien auch statische Inhaltsseiten in der Suche berücksichtigt, beispielsweise „Über uns", AGB oder Impressum. **Beispielkonfiguration** ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} index_configs: content: enabled: true custom_config: search_fields: - field: title - field: content display_fields: - field: source - field: title search_config: exact: enabled: true boost: 2.0 tie_breaker: 0.3 ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `enabled` | Aktiviert die Suche im Content-Index für den jeweiligen Subshop. | | `custom_config` | Konfigurationsblock für die Inhaltsseiten-Suche. | | `search_fields` | Liste der Felder, die für die Volltextsuche im Content-Index herangezogen werden. Beim Content-Index sind diese Felder fest vorgegeben, beispielsweise `title` und `content`. | | `display_fields` | Liste der Felder, die in der Suchantwort enthalten sein müssen, beispielsweise `source` zum Nachladen des Inhalts und `title` als Label. Auch hier sind die Felder fest je Index-Art definiert. | | `search_config` | Optionaler Konfigurationsblock zur Steuerung der Sucharten für den Content-Index. Analog zur [Basiskonfiguration des Suchmoduls](#basiskonfiguration-des-suchmoduls-search_config) können die einzelnen Sucharten (`exact`, `prefix`, `wildcard`, `ngram`, `fuzzy`) gezielt aktiviert, deaktiviert und gewichtet werden. | **Mehrere Content-Quellen aktivieren** Pro Content-Quelle aus dem Importmodul brauchen Sie hier einen eigenen Eintrag. Auch im Suchmodul wird `content` dazu zu einer Liste. ```yaml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} index_configs: content: - name: static enabled: true custom_config: search_fields: - field: title - field: content display_fields: - field: source - field: title - name: blog enabled: true custom_config: search_fields: - field: title - field: content display_fields: - field: source - field: title - name: magazin enabled: true custom_config: search_fields: - field: title - field: content display_fields: - field: source - field: title ``` **Parameterbeschreibung** | **Parameter** | **Beschreibung** | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | Name der Content-Quelle. Muss mit dem `name` im [Importmodul](#mehrere-content-quellen-für-die-suche) übereinstimmen, sonst findet das Suchmodul den zugehörigen Index nicht. | | `enabled` | Aktiviert die Suche in dieser Quelle. | | `custom_config` | Optional. Ohne Angabe verwendet das Suchmodul die Standardkonfiguration des Content-Index. Sie können pro Quelle eine eigene `search_config` und eigene Gewichtungen setzen, beispielsweise um Blog-Treffer schwächer zu gewichten als die statischen Seiten. | Eine Quelle erscheint nur in den Suchergebnissen, wenn der zugehörige Index in Elasticsearch tatsächlich existiert. Läuft der Import einer Quelle nicht oder ist er im Importmodul nicht aktiviert, verschwindet die Quelle ohne Fehlermeldung aus den Ergebnissen. Aktivieren Sie eine Quelle daher immer in beiden Modulen und prüfen Sie danach im Shop, ob Treffer geliefert werden. **Aufbau der Suchantwort** Bei mehreren Content-Quellen liefert die Suche die Treffer nicht mehr flach unter `content`, sondern verschachtelt pro Quelle. Unterhalb von `content` steht je Quelle ein Block mit den Treffern (`results`) und der Trefferzahl (`sub_total`). Die Gesamttrefferzahl `total` summiert weiterhin über alle Indizes. Die WebComponents erkennen dieses Format automatisch. Werten Sie die Suchantwort dagegen selbst aus, müssen Sie die Verschachtelung berücksichtigen. Ein Beispiel finden Sie unter [ws-search-result](/ws-search/integration-in-die-templates-storefront/webcomponents/ui-komponenten/ws-search-result). # WEBSALE | search Source: https://dokumentation.websale.de/ws-search/websale-search Aktivierung, Nutzungsoptionen und Templateeinbindung des Moduls WEBSALE | search mit Suggest, After-Search-Navigation, Filter- und Sortierfunktionen. Diese Dokumentation beschreibt die Aktivierung und Konfiguration des Moduls **WEBSALE | search**, die Bereitstellung der notwendigen Daten sowie die Integration der Suchfunktion in die Templates eines WEBSALE Onlineshops. Das Modul ermöglicht eine leistungsstarke Produktsuche mit Filter- und Sortiermöglichkeiten, die durch flexible WebComponents direkt in der Storefront abgebildet werden. *** ## Aktivierung des Moduls ### Auftragserteilung und Aktivierung Die Aktivierung des Such-Moduls erfolgt über das WEBSALE-Beauftragungsportal. Bitte folgen Sie diesen Schritten: 1. Melden Sie sich im [WEBSALE-Beauftragungsportal](https://websale.atlassian.net/servicedesk/customer/portal/12) an. 2. Wählen Sie den Menüpunkt "Zusatzmodule" oder "Data Flow Manager". 3. Füllen Sie den Antrag vollständig aus und wählen Sie "WEBSALE|Search" aus . Die Aktivierung erfolgt erst nach erfolgreicher Bearbeitung des Antrags durch WEBSALE. ### Nutzungsoptionen bei der Aktivierung Bei der Aktivierung des Such-Moduls stehen Ihnen folgende Nutzungsoptionen zur Verfügung. Sie können flexibel wählen, welche Funktionen Sie nutzen möchten: 1. **Nur Suchergebnisse mit Suggestfunktion und After-Search-Navigation:** * Diese Option aktiviert das Such-Modul ausschließlich für die Darstellung von Suchergebnissen. * Enthält die Suggestfunktion (automatische Vorschläge während der Eingabe) und die After-Search-Navigation (Filter- und Sortiermöglichkeiten, die nach der Suche angezeigt werden). 2. **Nur Filter- und Sortierfunktionen in Kategorien:** * In dieser Variante wird das Such-Modul ausschließlich für Kategorien eingesetzt. * Es übernimmt die Filter- und Sortiermöglichkeiten in den Kategorien und ersetzt die [**WEBSALE Standard-Filterung**](https://doku.websale.net/index.html?guide_filter_auf_kategorieebene.html) und [**WEBSALE Standard-Sortierung**](https://doku.websale.net/index.html?guide_sortieren_von_produktlisten.html). 3. **Kombinierte Nutzung:** * Sie können das Such-Modul sowohl für die Suche mit Suggestfunktion und After-Search-Navigation als auch für die Filter- und Sortierfunktionen in Kategorien aktivieren. **Wichtig!**
    Bitte geben Sie bei der Antragstellung klar an, welche der oben genannten Optionen Sie nutzen möchten. Jede Option kann einzeln oder kombiniert aktiviert werden.
    ## Weiterführende Links [Konfiguration des Such-Moduls](/ws-search/konfiguration-des-such-moduls) [Datenfeed-Einrichtung](/ws-search/datenfeed-einrichtung) [Integration in die Templates (Storefront)](/ws-search/integration-in-die-templates-storefront) # Changelog Source: https://dokumentation.websale.de/changelog Fortlaufende Übersicht über neue Funktionen, Verbesserungen und Fehlerbehebungen der WEBSALE-Software, geordnet nach Release-Version. Auf dieser Seite dokumentieren wir fortlaufend alle Änderungen an der WEBSALE-Software, darunter neue Funktionen im Shop und im Admin-Interface sowie Verbesserungen und Fehlerbehebungen. Die Einträge sind nach der Release-Version geordnet, wobei die neueste Version oben steht. **Breaking Changes** - also Änderungen, die eine Anpassung bestehender Shops oder Templates erforderlich machen können, kennzeichnen wir in jedem Release deutlich mit einer Warnung. Enthält ein Release keinen solchen Hinweis, sind i.d.R. keine Anpassungen nötig. **Fehlerbehebungen** * **PayPal: Ausstehender Zahlungseinzug wird nicht mehr abgelehnt.** Ein Zahlungseinzug (Capture) im Status „Pending" wurde abgelehnt, obwohl der Betrag bereits eingezogen war. Solche Zahlungen werden jetzt korrekt weiterverarbeitet. Die in release-1.94 eingeführte Ablehnung nicht abgeschlossener Zahlungen greift damit nur noch bei Zahlungen, die tatsächlich nicht eingezogen wurden. * **PayPal: Weiterleitung bei abgelehnter oder fehlerhafter Zahlung.** Lehnt PayPal eine Zahlung ab oder tritt beim Bezahlvorgang ein Fehler auf, wird der Kunde jetzt auf die richtige Seite geleitet. * **Bestellprüfung: Laufende Bestellvorgänge werden nicht mehr abgebrochen.** Die automatische Bestellprüfung hat Bestellvorgänge beendet, die gerade noch liefen. Das passiert nicht mehr. * **Direktbestellung: Fehlermeldung erscheint nur noch im Fehlerfall.** Bei der Direktbestellung wurde eine Fehlermeldung dauerhaft und doppelt ausgegeben. Sie erscheint jetzt nur noch einmal und nur dann, wenn tatsächlich ein Fehler auftritt. * **Gutscheine: Datenbankfehler behoben.** Eine fehlerhafte Datenbankabfrage in der Gutscheinverarbeitung führte zu einem Fehler. * **Gutscheine: Kein Gutschein-Link in abgebrochenen Bestellungen.** Die Bestelldaten einer abgebrochenen Bestellung enthielten weiterhin den Download-Link des gekauften Gutscheins. * **Passwort zurücksetzen: Automatische Anmeldung wird beendet.** Beim Zurücksetzen des Passworts über den E-Mail-Link blieben die Token für „Angemeldet bleiben" bestehen. Eine bestehende automatische Anmeldung überdauerte damit das Zurücksetzen. Die Token werden jetzt gelöscht. * **Länderprüfung: Deaktivierte Länder werden berücksichtigt.** Die Länderprüfung hat auch Länder akzeptiert, die im Shop deaktiviert sind. * **Merklisten: Standard-Merkliste lässt sich nicht mehr löschen.** Die Standard-Merkliste konnte gelöscht werden, obwohl der Shop sie benötigt. * **Produktbewertungen: `checkRatingExistence()` liefert korrekte Werte.** Die Prüfung `$wsProductRating.checkRatingExistence()` gab immer `true` zurück, unabhängig davon, ob eine Bewertung vorlag. * **Produktbewertungen: Bearbeitungsformular bleibt nicht mehr leer.** Steht `allowRatingAfterEachOrder` auf `false`, wurde ein leeres Bearbeitungsformular angezeigt. * **Produktbewertungen: Bewertungen durch Unterkonten.** Bei Unterkonten widersprachen sich die Existenzprüfung des Mitglieds und der eindeutige Datenbankindex. Das führte zu Fehlern beim Bewerten. * **Storefront-API: Bewertungen eines Kundenkontos werden geliefert.** Statt der Bewertungen eines Kundenkontos gab die Storefront-API `null` zurück. * **Storefront-API: Kennzeichen des Adresstyps werden geliefert.** Bei `loadAddress()` und bei den Standardadressen fehlten die Kennzeichen des Adresstyps, die Storefront-API gab `null` zurück. * **REST-API: Korrekte Liste bei Abfragen ohne Subshop-ID.** Fehlte der Parameter mit der Subshop-ID, lieferte die REST-API die falsche Liste. * **Kundendaten-Import: Leere Felder überschreiben keine Daten mehr.** Der Import von Kundendaten im Admin-Interface überschreibt bestehende Werte nicht mehr mit leeren Feldern. * **Logmanager: Benachrichtigungen decken den aktuellen Zeitraum ab.** Der Zeitraum einer Benachrichtigung wurde aus dem letzten Versand plus dem Intervall berechnet. Die E-Mails bezogen sich dadurch dauerhaft auf länger vergangene Zeitfenster und holten den aktuellen Stand nie ein. * **Statistik: Aggregator bricht nicht mehr unbemerkt ab.** Der Statistik-Aggregator brach unter Umständen ohne Fehlermeldung ab. * **Weitere kleinere Fehlerbehebungen im Admin-Interface.** **Neu im Shop** * **Dynamisches CMS-Seitentemplate für statische Shopseiten.** Statische Shopseiten lassen sich jetzt über ein dynamisches CMS-Seitentemplate ausgeben. Für neue Inhaltsseiten muss damit kein eigenes Template mehr angelegt werden. * **Computop: Seite für ausstehende Zahlungen.** Für Computop-Zahlungen gibt es jetzt eine eigene Seite für ausstehende Zahlungen. Kunden sehen damit auch bei Computop einen klaren Zwischenstand, solange eine Zahlung noch nicht abgeschlossen ist. * **Storefront-API: Textsuche.** Die Storefront-API bietet jetzt eine Textsuche. * **Storefront-API: Weiterleitung für gelöschte Produkte.** Ruft ein Kunde ein gelöschtes Produkt auf, liefert die Storefront-API jetzt eine Weiterleitung. **Neu im Admin-Interface** * **Validierungen: Konfiguration über IDs und Knoten-Namen.** Validierungen lassen sich jetzt sowohl über IDs als auch über Knoten-Namen konfigurieren. **Fehlerbehebungen** * **Produktliste: Blätterung funktioniert wieder korrekt.** * **Versandarten: Validierung der Liefermethode korrigiert.** Die Prüfung der gewählten Liefermethode funktioniert wieder korrekt. * **Stripe: Seite für ausstehende Zahlungen wird korrekt angezeigt.** * **Stripe: Zahlungsstatus wird korrekt ermittelt.** * **Bancontact: Weiterleitung auf die Seite für ausstehende Zahlungen korrigiert.** Bancontact-Zahlungen führten fälschlich auf die PayPal-Seite für ausstehende Zahlungen. * **Datei-Exporter (Reporter): kein voreingestellter Filter mehr.** Beim Anlegen eines Exports ist jetzt kein Filter mehr vorbelegt. * **Kundendaten-Import: Fehler behoben.** Ein Fehler im Import von Kundendaten wurde behoben. * **Merkliste: Fehler behoben.** Ein Fehler in der Produkt-Merkliste wurde behoben. * **Aufgabenverwaltung: Verwaiste Einträge werden aufgeräumt.** Nicht mehr zugeordnete Einträge in der internen Aufgabenliste bleiben nicht länger liegen. * **Währungen: Währungssymbol muss nicht mehr eindeutig sein.** Mehrere Währungen dürfen jetzt dasselbe Symbol verwenden. **Breaking Change: Manuelle Migration und Template-Anpassungen erforderlich.** Dieses Release setzt eine manuelle Migration sowie kleinere Anpassungen an den Templates voraus. Planen Sie das Update entsprechend ein und stimmen Sie es ab, bevor Sie es in einen produktiven Shop einspielen. **Neu im Admin-Interface** * **Multiselect-Suche bei umfangreichen Filterlisten.** Enthält ein Filter viele Einträge, lässt sich die passende Auswahl jetzt über eine Suche eingrenzen. * **Logmanager: Subshop-ID ist optional.** Die Subshop-ID ist im Logmanager kein Pflichtfeld mehr. **Fehlerbehebungen** * **Kundendaten-Import: Passwörter bleiben erhalten.** Ein manueller Import von Kundendaten löscht bestehende Passwörter nicht mehr. * **B2B-Warenkorb: Subshop-Überschreibungen werden übernommen.** Der B2B-Warenkorb berücksichtigt subshopspezifische Überschreibungen jetzt korrekt. * **Inventar-Konfiguration: Subshop-Überschreibungen werden übernommen.** Subshopspezifische Überschreibungen der Inventar-Konfiguration werden jetzt korrekt berücksichtigt. * **Checkout: Weiterleitung auf die Seite für ausstehende Zahlungen.** Bricht ein Kunde den Bezahlvorgang ab, wird er jetzt zuverlässig auf die Seite für ausstehende Zahlungen geleitet. * **E-Mail-Adressen: Groß- und Kleinschreibung wird ignoriert.** E-Mail-Adressen werden in der Datenbank jetzt unabhängig von Groß- und Kleinschreibung behandelt. * **Kundendaten-Import: keine Fehler bei leerer Telefonnummer.** Der Import von Kundendaten schlägt bei einer leeren Telefonnummer nicht mehr fehl. * **REST-API: Leere Arrays in Konfigurationen bleiben erhalten.** Beim Speichern von Konfigurationen über die REST-API werden leere Arrays nicht mehr als `null` gespeichert. * **Storefront-API: `checkout/commitDraftAddress.htm` funktioniert wieder korrekt.** * **Storefront-API: `watchList/checkHasProduct.htm` funktioniert wieder korrekt.** * **Admin-Interface: Fehlermeldung bei gesperrtem Kundenkonto.** Die Meldung zu einem gesperrten Kundenkonto wird beim Login jetzt korrekt angezeigt. **Neu im Shop** * **PayPal Checkout Vault: Gespeicherte Zahlungsdaten für schnelleren Checkout.** Kunden können ihre PayPal-Zahlungsdaten jetzt sicher hinterlegen und bei einer späteren Bestellung wiederverwenden. Das beschleunigt den Bezahlvorgang für wiederkehrende Kunden. * **Textbausteine: Subshop-spezifische Ausnahmen innerhalb einer Sprache.** Innerhalb einer Sprache lassen sich einzelne Textbausteine jetzt je Subshop abweichend definieren. So kann ein Subshop einen abweichenden Text verwenden, ohne die Sprache insgesamt zu duplizieren. * **Textbausteine: Import und Export.** Textbausteine lassen sich jetzt importieren und exportieren, beispielsweise um sie extern zu bearbeiten oder zwischen Shops zu übertragen. * **Gutscheinfehler: Mehrere Fehlergründe gleichzeitig.** Erreicht ein Gutschein den Mindestbestellwert nicht und liegen zugleich keine passenden Produkte im Warenkorb, werden jetzt beide Fehlergründe gleichzeitig angezeigt. Die Funktion baut auf der in release-1.93 eingeführten Ausgabe von Gutscheinfehlern auf. **Neu im Admin-Interface** * **Kundenübersicht: Letztes Änderungsdatum.** Die Kundenübersicht zeigt jetzt zu jedem Kunden das Datum der letzten Änderung an. **Fehlerbehebungen** * **PayPal: Nicht abgeschlossene Zahlungen werden abgelehnt.** Zahlungen, die nicht erfolgreich eingezogen (captured) werden konnten, werden jetzt abgelehnt, statt in einem unklaren Zustand zu verbleiben. * **REST-API: Set-Produkte mit ungültigen IDs werden abgelehnt.** Enthält ein Set-Produkt ungültige Produkt-IDs, wird es über die REST-API jetzt abgelehnt, statt fehlerhaft angelegt zu werden. * **Produktsuche: Speicherfehler beim Indexieren behoben.** Der Such-Indexer läuft bei großen Datenmengen nicht mehr in einen Speicherüberlauf (Out of Memory). * **Produkt-Import/-Export: Variantenfelder werden nicht mehr geleert.** Beim CSV-Import bzw. -Export wurden Variantenfelder unter Umständen mit leeren Werten überschrieben. Das passiert nicht mehr. * **Migrator: Sauberes Aufräumen bei Abbruch.** Bricht der Migrator mit einem Fehler ab, räumt er die begonnenen Änderungen jetzt korrekt auf. **Breaking Change: Der AccountType wird nicht mehr aus dem Template übernommen.** Der Shop leitet den Kundentyp jetzt selbst aus dem Status der Session ab. Die Auswahl des AccountType im Template bleibt aus Kompatibilitätsgründen und für die Template-State-Machine erhalten, hat auf den Shop aber keine Auswirkung mehr. Templates, die den Bestellablauf über diese Auswahl gesteuert haben, sollten geprüft werden. **Neu im Shop** * **Gutscheine: Überarbeitete Oberfläche und aussagekräftige Fehlermeldungen.** Die Darstellung und Bedienung von Gutscheinen im Bestellablauf wurde überarbeitet. Zusätzlich lässt sich jetzt die Art des Gutscheinfehlers ausgeben, beispielsweise wenn ein Gutschein den Mindestbestellwert nicht erreicht oder im Warenkorb keine passenden Produkte liegen. Die Fehlertexte pflegen Sie im neuen Konfigurationsknoten [`checkout.voucherErrors`](/konfiguration/checkout-bestellablauf#checkout-vouchererrors-fehlertexte-zu-wirkungslosen-gutscheinen), im Template steht die Fehlerliste unter `$wsCheckout.ineffectiveVoucherErrors`. * **Zahlungsstatus im Shop abfragen.** Die neue Aktion `refreshPaymentStatus` ermittelt den aktuellen Zahlungsstatus der laufenden Bestellung und gibt ihn zurück. Damit lässt sich beispielsweise auf der Seite für ausstehende Zahlungen prüfen, ob eine Zahlung inzwischen abgeschlossen wurde. **Neu im Admin-Interface** * **Manuelle Log-Suche: Filterung nach Programm.** In der manuellen Log-Suche lassen sich die Ergebnisse jetzt zusätzlich nach Programm einschränken. * **Zeitabhängige Preise: Promotion-Text anpassbar.** Zu jedem zeitgesteuerten Preis lässt sich jetzt ein eigener Promotion-Text pflegen, der im Shop zum Aktionspreis ausgegeben wird. **Fehlerbehebungen** * **Versandarten: AccountType wird aus der Session abgeleitet.** Der Shop hängt nicht mehr vom im Template ausgewählten AccountType ab, sondern leitet den Kundentyp aus dem Status der Session ab: * Nicht eingeloggt: Gastbestellung * Neu registriert: Neukunde * In eine bestehende Session eingeloggt: Bestandskunde Damit ist eine ganze Reihe von Fehlern behoben, bei denen Versandarten nicht angezeigt wurden. * **Bestellbestätigungsseite: Warenkorb wird zuverlässig geleert.** Eine Race Condition konnte dazu führen, dass der Warenkorb auf der Bestellbestätigungsseite noch Positionen enthielt. Der Warenkorb ist jetzt zuverlässig geleert. * **Produktdatenfelder: Lange Listen verschieben das Design nicht mehr.** Sehr lange Listen in den Produktdatenfeldern haben die Darstellung zerschossen. Das Layout bleibt jetzt stabil. **Neu im Shop** * **Werbemittelkennzeichen (Inserts): Bestellquelle über Katalog-Codes erfassen.** Über Katalog-Codes lässt sich jetzt erfassen und weitergeben, über welches Werbemittel (Insert) eine Bestellung ausgelöst wurde. So kann die Herkunft einer Bestellung ausgewertet werden. **Neu im Admin-Interface** * **Elasticsearch: Konfigurierbarer Log-Index.** Der Ziel-Index bzw. Data Stream, aus dem die Shop-Logs gelesen werden, lässt sich jetzt über die neue Option `logsIndex` unter `elasticSearch` in der `shop.json` festlegen, beispielsweise um die Elasticsearch-Standard-Data-Streams (`logs-*-*`, ab Elasticsearch 8) zu nutzen. Ohne Konfiguration bleibt der bisherige Index `logs` aktiv. ```json shop.json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}} { "elasticSearch": { "url": "", "logsIndex": "logs-vx-default" } } ``` **Fehlerbehebungen** * **Merklisten: Inhalt bleibt erhalten.** Der Inhalt von Merklisten verschwindet nicht mehr nach einiger Zeit. * **Gespeicherte Warenkörbe: keine leeren Einträge für Gäste.** Für Gast-Nutzer werden keine leeren Einträge für gespeicherte Warenkörbe mehr angelegt. * **Admin-Interface: kein Logout bei fehlenden Berechtigungen.** Fehlen einem Benutzer Berechtigungen, wird er im Admin-Interface nicht mehr abgemeldet. * **Admin-Interface: keine Vorauswahl aller Custom-Produktfelder.** Beim Öffnen werden nicht mehr automatisch alle benutzerdefinierten Produktfelder ausgewählt. * **Daten-Subshops: Referenzierung korrigiert.** Die Referenzierung von Daten-Subshops funktioniert wieder korrekt. * **Konfigurationsdienst: leere Listen bleiben Listen.** Eine leere Liste wird im Konfigurationsdienst nicht mehr fälschlich in `null` umgewandelt. **Fehlerbehebungen** * **PayPal-Rechnungskauf: Kunde bleibt nicht mehr auf der „Pending"-Seite hängen.** Trifft die PayPal-Benachrichtigung (Webhook) vor der Rückkehr des Kunden in den Shop ein, wird die Bestellung jetzt korrekt abgeschlossen. Der Kunde bleibt nicht länger auf der Seite für ausstehende Zahlungen stehen. * **Weitere Fehlerbehebungen aus Shop-Tests.** Verschiedene kleinere Fehler, die im Rahmen von Shop-Tests gefunden wurden, sind behoben. **Neu im Admin-Interface** * **Statistik: Automatisierte Währungsumrechnung.** Der Statistik-Dienst rechnet Umsätze in Fremdwährungen jetzt automatisch um. Auswertungen über Shops mit mehreren Währungen liefern damit einheitliche, vergleichbare Werte. **Fehlerbehebungen** * **Feed Builder: Speicherproblem behoben.** Ein Memory Leak im Feed Builder wurde beseitigt, das bei lang laufenden Feed-Erzeugungen zu erhöhtem Speicherverbrauch führen konnte. * **PayPal: „Pending Payment"-Seite mit SEO-URLs.** Die Seite für ausstehende Zahlungen beim PayPal-Rechnungskauf funktioniert jetzt auch in Shops mit aktivierten SEO-URLs korrekt. * **PayPal Express Checkout: Keine doppelten Adressen mehr.** Der PayPal Express Checkout legt beim Bezahlvorgang keine duplizierte Adresse mehr im Kundenkonto an. **Neu im Shop** * **Zahlungsarten: Platzierungsabhängige Anzeige von Icons und Beschreibungstexten.** Icons und Beschreibungstexte von Zahlungsarten lassen sich jetzt abhängig vom Anzeigeort (beispielsweise Bestellablauf, Footer) unterschiedlich darstellen. * **Bestellablauf: Automatische Vorbelegung der Versandart bei Adressänderung.** Ändert ein Kunde im Bestellablauf seine Lieferadresse, wird die passende Versandart automatisch vorbelegt. * **Bestellablauf: Automatische Vorbelegung der Zahlungsart bei Adressänderung.** Ändert ein Kunde im Bestellablauf seine Adresse, wird die passende Zahlungsart automatisch vorbelegt. **Neu im Admin-Interface** * **REST-API: Laden von Produkt-IDs ohne Produktdaten.** Die REST-API kann jetzt auf Wunsch ausschließlich Produkt-IDs liefern. * **Varianten: Konfigurierbare Anzeigereihenfolge von Variantenwerten.** Die Reihenfolge, in der Variantenwerte innerhalb einer Variantengruppe angezeigt werden, ist jetzt konfigurierbar. * **Bestelldaten: Download-Link für Gutscheine.** Bei Bestellungen mit gekauften Gutscheinen wird der Download-Link des Gutscheins jetzt direkt in den Bestelldaten angezeigt. **Fehlerbehebungen** * **Produktanlage: Inventar-Eintrag wird korrekt erstellt.** Beim Anlegen neuer Produkte wird der zugehörige Inventar-Eintrag jetzt zuverlässig angelegt. **Neu im Admin-Interface** * **Filialen und Märkte grafisch verwalten.** Filialen bzw. Märkte lassen sich jetzt direkt im Admin-Interface über eine grafische Oberfläche anlegen und verwalten. * **Logmanager: Benachrichtigungsstatus und Direktsteuerung von Log-Gruppen.** In der Übersicht des Logmanagers ist jetzt der Benachrichtigungsstatus jeder Log-Gruppe sichtbar; Log-Gruppen lassen sich direkt aus der Übersicht heraus steuern. * **Logmanager: Zeitraum-Filterung bis auf Stunden und Minuten.** Der Zeitraum-Filter im Admin-Interface lässt sich jetzt nicht mehr nur tagesgenau, sondern bis auf Stunden und Minuten genau einstellen. * **Logmanager: Zeitpunkt in der manuellen Log-Suche vorausgewählt.** Bei der manuellen Log-Suche ist der Zeitpunkt jetzt standardmäßig vorbelegt, das spart einen Eingabeschritt bei jeder Suche. * **Logmanager: Fehlerbenachrichtigung erneut senden.** Konnte eine Benachrichtigungs-E-Mail bei einem Fehler nicht zugestellt werden, lässt sie sich jetzt erneut senden. **Fehlerbehebungen** * **Zahlungsarten: Wechsel auf Offline-Zahlungsart nach fehlgeschlagener Online-Zahlung.** Schlägt eine Online-Zahlungsart fehl, kann der Kunde die Bestellung jetzt zuverlässig mit einer Offline-Zahlungsart abschließen. * **Produktimport: `id` beim Update nicht mehr fälschlich als fehlerhaft markiert.** Beim Aktualisieren von Produkten über den Produktimport wird das Feld `id` nicht mehr fälschlicherweise als Fehler gemeldet. * **Gutscheine: Korrekte Berechnung des Mehrwertsteuerabzugs.** Gutscheine mit Mehrwertsteuerabzug erzeugen keinen fehlerhaften negativen bzw. positiven Mehrwertsteuerabzug mehr. * **PayPal-Rechnungskauf mit Gutscheinen.** Ein Fehler beim PayPal-Rechnungskauf (Pay Upon Invoice) in Kombination mit Gutscheinen wurde behoben. * **PayPal-Rechnungskauf: PaymentId in den Bestelldaten.** Beim PayPal-Rechnungskauf wird die PaymentId jetzt korrekt in die Bestelldaten übernommen. # FAQ - Häufig gestellte Fragen Source: https://dokumentation.websale.de/faq-haufig-gestellte-fragen Antworten auf häufig gestellte Fragen rund um die Arbeit mit dem WEBSALE-Shopsystem: Einstieg, Strapi CMS, Templates, Konfiguration, Datensicherung und Tagesgeschäft. Auf dieser Seite sind die häufig gestellten Fragen rund um das Arbeiten mit dem WEBSALE Shopsystem gesammelt und beantwortet. Ziel ist es, schnelle Hilfe zu bieten – von typischen Einstiegsfragen bis zu wiederkehrenden Themen aus dem täglichen Arbeiten. *** ## Strapi CMS Hier finden Sie Antworten zu häufig gestellten Fragen rund um das [Headless CMS Strapi](/strapi-cms). Ziel ist es, schnelle Hilfe zu bieten – von typischen Einstiegsfragen bis zu wiederkehrenden Themen aus dem täglichen Arbeiten mit dem CMS System. ### Gibt es Zugriff auf den Node.js-Server? Ein direkter Zugriff auf den NodeJS Server ist derzeit nicht möglich und auch in näherer Zukunft nicht geplant. *** ### Wie kann Content in den Content Manager importiert werden? Das aktuell implementierte Importkonzept von Strapi erlaubt es, Daten aus einer Strapi-Instanz zu exportieren und in eine andere Instanz zu importieren, da die Datenstrukturen konsistent sind. Importe von statischem Content in Strapi sind grundsätzlich möglich, allerdings muss der Content strukturiert sein, um eine spätere Bearbeitung zu ermöglichen. Um Inhalte in Strapi importieren zu können, müssen die entsprechenden Strukturen (z.B. [Komponenten und Eingabemasken](/strapi-cms/komponenten-sammlungen-in-strapi)) mit übergeben werden. Diese Strukturen ermöglichen es, die Inhalte in Strapi anzuzeigen und zu bearbeiten. Wir benötigen daher detaillierte Informationen über die Art der Inhalte, die importiert werden sollen (z.B. Textinhaltsseiten, Navigationsstrukturen etc.). *** ### Können Lifecycle Hooks verwendet werden? Nein. Strapi bietet Lifecycle Hooks an, die es ermöglichen, bestimmte Aktionen auszuführen, wenn Inhalte geändert oder erstellt werden. In unserem WEBSALE-System ist Strapi jedoch so integriert, dass es statische Inhalte auf den Server exportiert. Diese Inhalte werden dann im Shop angezeigt. Änderungen in Strapi müssen daher exportiert und an den Shop übergeben werden, um sichtbar zu werden. Da der Shop selbst nicht direkt mit Strapi kommuniziert, ist die Verwendung von Lifecycle Hooks nicht möglich. *** ### Welche Benutzerrechte stehen zur Verfügung? Der initiale Account ist immer als SuperAdmin freigeschaltet, wodurch dieser Account alle Rechte hat. Dier Account kann dann weitere Benutzer resp. Acccounts hinzufügen, bei denen unterschiedliche Rechte vergeben werden können. Mehr Informationen dazu finden Sie [hier](/strapi-cms/anmeldung-benutzerverwaltung-von-strapi). *** ### Ist ein direkter Upload in die Strapi-Medienbibliothek möglich? Nein. Ein Upload von Bildern ist nur über Strapi selbst möglich. Generell dürfen auch nur dort Bilddaten, wie beispielweise der Name angepasst werden. *** ### Wie funktionieren Bild-Varianten und unterschiedliche Größen? Standardmäßig ist der [Bildkonverter](/admin-interface) so konfiguriert, dass hochgeladene Bilder in derselben Größe, aber in einem anderen Dateiformat ausgegeben werden. Sie können die Konfigurationsdatei des Bildkonverters nach Ihren Wünschen anpassen, was die Auflösung und Qualität der Bilder betrifft. Dabei ist jedoch stets darauf zu achten, dass die Pfade in der Konfigurationsdatei nicht geändert werden dürfen. *** ### Gibt es Zugang zum Strapi-Server? Nein. Ein direkter Zugriff auf den Strapi-Server ist nicht vorgesehen. Durch die Auslieferung von Strapi im Development-Mode ist es dennoch möglich, Inhaltselemente ohne WEBSALE zu erstellen, anzupassen und zu erweitern. Die Übertragung der [strukturierten JSON-Dateien](/schnittstellen/externe-datenschnittstelle-datei-bucket-basiert) von erstellten Inhalten auf den Objektspeicher S3 erfolgt automatisch. *** ### Welche Datenbank wird für Strapi verwendet? Für Strapi verwenden wir sqlite3. *** *** ## Datenzugriff und Externe Daten ### Warum gibt `$wsExternalData.load(file, options)` `null` zurück? Wenn `$wsExternalData.load(file, options)` `null` zurückgibt, wurde die Datei unter dem angegebenen Pfad nicht gefunden. Häufige Ursachen sind ein falsches Verzeichnis bzw. ein falscher Pfad, Schreibfehler (Verzeichnis, Pfad oder Dateiname) oder die Datei ist nicht auf dem Server vorhanden. Zur Prüfung gibt es zwei Möglichkeiten: Entweder im entsprechenden [S3-Bucket](/schnittstellen/externe-datenschnittstelle-datei-bucket-basiert) nachsehen, ob die Datei unter dem angegebenen Verzeichnis/Pfad existiert, oder – ohne S3-Zugriff – den Inhalt des Verzeichnisses mit `$wsExternalData.read(path, options)` ausgeben lassen und prüfen, ob der erwartete Dateiname enthalten ist (siehe Parameterbeschreibung zu `read`). Mehr Informationen zu `$wsExternalData.read(path, options)` finden Sie: * Datenzugriff & Anzeige → [\$wsExternalData - Externe Daten](/frontend/referenz/module/wsexternaldata) * Referenz → Module → [\$wsExternalData](/frontend/referenz/module/wsexternaldata) *** ## Datensicherung und Backups Hier finden Sie Antworten dazu, wie lange WEBSALE Sicherungen Ihres Shops vorhält und was das für die Wiederherstellung eines früheren Stands bedeutet. ### Wie lange werden Backups des Shopsystems aufbewahrt? WEBSALE sichert das System, auf dem Ihr Shop und die zugehörigen Anwendungen laufen, automatisch. Diese Backups werden für 3 Monate aufbewahrt. *** ### Wie kann ein früherer Stand aus einem Backup wiederhergestellt werden? Wenn Sie ein Backup benötigen, wenden Sie sich über das [Kontaktformular im WEBSALE Service Desk](https://websale.atlassian.net/servicedesk/customer/portal/6) an den Support. *** ## Allgemeine Fragen zum Shop ### Was mache ich, wenn ich den Einladungslink zum Admin-Interface des Shops verloren habe? Wenn Sie Ihren Einladungslink zum Admin-Interface Ihres Shopsystems verloren haben, können Sie über den Link "Passwort vergessen?" und der Eingabe Ihrer verknüpften E-Mail-Adresse einen Wiederherstellungslink beantragen. Eine andere Möglichkeit ist Ihren Vertrieb zu bitten, über das Admin-Interface einen erneuten Versand der E-Mail auszulösen. # Glossar: Fachbegriffe der WEBSALE-Dokumentation Source: https://dokumentation.websale.de/glossar Erklärungen zentraler Fachbegriffe rund um WEBSALE, darunter ASSE, Consent, Cookie, Template-Code, Referrer und weitere Konzepte des Shops. In diesem Glossar werden Fachbegriffe erklärt, die in der WEBSALE-Dokumentation vorkommen. Es richtet sich an alle, die mit dem Shop arbeiten. *** ## Allgemeine Begriffe ## ASSE Abkürzung für *Asynchronous Server-Side Events*. Ein vom Shop ausgelöstes Ereignis, das im Hintergrund einen HTTP-Request an eine konfigurierte externe URL sendet, z. B. um nach einer Bestellung Daten an einen Tracking-Dienst zu übermitteln. „Asynchron" bedeutet, dass der Request zeitversetzt versendet wird. Der auslösende Seitenaufbau wartet nicht auf die Antwort. Ausgelöst werden ASSE-Events im Template über [`$wsAsse`](/frontend/referenz/module/wsasse), eingerichtet werden sie in der [ASSE-Konfiguration](/konfiguration/general-allgemeine-shopeinstellungen#4-general-asse-schnittstelle-für-asynchronous-server-side-events-asse). ### ASSE Abkürzung für *Asynchronous Server-Side Events*. Ein vom Shop ausgelöstes Ereignis, das im Hintergrund einen HTTP-Request an eine konfigurierte externe URL sendet, z. B. um nach einer Bestellung Daten an einen Tracking-Dienst zu übermitteln. „Asynchron" bedeutet, dass der Request zeitversetzt versendet wird. Der auslösende Seitenaufbau wartet nicht auf die Antwort. Ausgelöst werden ASSE-Events im Template über [`$wsAsse`](/frontend/referenz/module/wsasse), eingerichtet werden sie in der [ASSE-Konfiguration](/konfiguration/general-allgemeine-shopeinstellungen#4-general-asse-schnittstelle-für-asynchronous-server-side-events-asse). ### Consent Die ausdrückliche Zustimmung eines Besuchers, dass der Shop bestimmte Cookies setzen oder Daten verarbeiten darf. Für technisch notwendige Cookies ist sie nicht erforderlich, für Marketing- und Tracking-Cookies dagegen in der Regel Pflicht (DSGVO). Im Template prüfen Sie die Zustimmung mit `$wsConsent.checkAllowed()`, bevor Sie ein nicht-notwendiges Cookie setzen. Details: [\$wsConsent](/frontend/referenz/module/wsconsent). ### Cookie Eine kleine Information, die der Browser pro Website speichert und über mehrere Seitenaufrufe hinweg behält, zum Beispiel eine gewählte Einstellung oder eine Kennung. Ohne Cookie „vergisst" der Shop bei jedem Seitenaufruf alles Vorherige. In WEBSALE lesen und setzen Sie Cookies über das Modul [\$wsCookie](/frontend/referenz/module/ws-cookie-browser-cookie). ### Flag Ein Flag ist ein einfacher Markierungswert, der einen Zustand festhält, meist mit nur zwei möglichen Werten wie „ja/nein" oder „gesehen/nicht gesehen". Der Begriff kommt vom englischen Wort für „Fähnchen": Es ist entweder gesetzt oder nicht. In WEBSALE begegnet Ihnen ein Flag zum Beispiel als Cookie-Wert, der festhält, ob ein Besucher ein Info-Popup bereits gesehen hat. Anhand des Flags entscheidet das Template, ob das Popup noch angezeigt wird. ### JSON Ein Textformat für strukturierte Daten wie Listen oder Schlüssel-Wert-Paare (die Abkürzung steht für „JavaScript Object Notation"). Es ist menschenlesbar und wird von vielen Werkzeugen verstanden. In WEBSALE werden komplexe Cookie-Werte (Listen, Maps) intern automatisch als JSON gespeichert. Auch externe Daten liegen häufig als JSON vor (siehe `$wsExternalData`, *Pfad prüfen*). ### Kampagnen-Link Ein Link zum Shop, der zusätzliche Informationen mitführt, meist als Parameter in der Adresse. Damit lässt sich erkennen, aus welcher Marketing-Aktion ein Besucher kommt, etwa aus einem Newsletter oder einer Anzeige. Ein Kampagnen-Link ist einer der typischen Auslöser, um ein Cookie zu setzen (Einstiegsweg). Verwandt: [Referrer](#referrer). ### Onsite-Personalisierung Das gezielte Ausspielen individueller Inhalte oder Angebote direkt auf den Shop-Seiten, abhängig vom Verhalten oder den Merkmalen eines Besuchers. **Abgrenzung:** Das bloße Speichern einer Einstellung in einem Cookie, etwa eine persönliche Begrüßung, ist für sich genommen noch keine Onsite-Personalisierung. (Doku-Seite *ergänzen, sobald vorhanden*.) ### Referrer Die Adresse der Seite, von der ein Besucher kommt. Klickt jemand auf einen Link zu Ihrem Shop, übermittelt der Browser meist die Adresse der vorherigen Seite. So erkennen Sie, woher der Besucher stammt. Der Referrer ist einer der typischen Auslöser, um ein Cookie zu setzen (Einstiegsweg). (Im technischen HTTP-Umfeld wird der Begriff auch „Referer" geschrieben.) ### Session-Cookie Ein Cookie ohne festgelegte Lebensdauer. Es besteht nur bis zum Schließen des Browsers und wird dann gelöscht. In WEBSALE entsteht ein Session-Cookie, wenn Sie beim Setzen keine Lebensdauer (`age`) angeben. Soll die Information länger erhalten bleiben, geben Sie eine Dauer an. Details: Modul [\$wsCookie](/frontend/referenz/module/ws-cookie-browser-cookie), Methode `setCookie`. ### Stylesheet Eine CSS-Datei, die das Aussehen der Seiten festlegt: Farben, Schriften, Abstände und Layout. Ein Wechsel des Stylesheets ändert das Erscheinungsbild, zum Beispiel von einer hellen auf eine dunkle Darstellung. *** ## WEBSALE-spezifische Begriffe ### Template-Code Code in den WEBSALE-Templates (den `.htm`-Dateien), der beim **Seitenaufbau** auf dem Server ausgeführt wird, nicht erst beim Klick des Nutzers. Wichtige Folge: Aktionen wie das Setzen eines Cookies passieren während eines Seitenaufrufs, nicht im Moment des Klicks. Ein Klick wirkt erst, wenn er eine neue Anfrage auslöst und das Template dabei erneut durchläuft. (Konzept-Seite zu Templates *verlinken, sobald vorhanden*.) # Migration Source: https://dokumentation.websale.de/migration Strukturierte Migration zu WEBSALE: Daten, Prozesse und Schnittstellen vom Vorgängersystem oder aus älteren WEBSALE-Versionen planen und sicher umsetzen. In der E-Commerce-Welt sind Migrationen nichts Ungewöhnliches: Shops werden relauncht, Systeme werden abgelöst, neue Plattformen eingeführt. Gleichzeitig zeigt die Erfahrung, dass das Thema Migration in vielen Projekten unterschätzt wird. Werden zentrale Daten, Prozesse und Schnittstellen nicht frühzeitig betrachtet, kann dies zu Datenverlusten, Mehrarbeit im Tagesgeschäft und zu Frustration bei Kunden führen. WEBSALE verfügt über langjährige Erfahrung mit Systemwechseln – sowohl von älteren WEBSALE Versionen auf die aktuelle Plattform als auch von anderen Shopsystemen zu WEBSALE. Diese Dokumentation soll dabei unterstützen, Migrationen strukturiert zu planen und umzusetzen, damit der Wechsel auf WEBSALE möglichst reibungslos verläuft. ## Inhaltsübersicht * [Daten-Migration](/migration/daten-migration) — Diese Seite beschreibt, wie bei einem Wechsel auf das WEBSALE Shopsystem (oder bei einem Versionswechsel innerhalb von WEBSALE) mit bestehenden Daten umgegangen wird. * [Migration WEBSALE V8s -> Neue Version](/migration/migration-websale-v8s-neue-version) — Diese Seite und ihre Unterseiten beschäftigen sich ausschließlich mit der Migration von Shops, die von der WEBSALE Version V8s auf die neue Version umgestellt werden. Sie bündeln die dafür relevanten Informationen, Hinweise und Migrationshilfen für die betroffenen Bereiche. # Daten-Migration Source: https://dokumentation.websale.de/migration/daten-migration Überblick zum Umgang mit bestehenden Daten beim Wechsel auf WEBSALE: Schnittstellen, Exporte, Konvertierung und führende Systeme im Vergleich. Diese Seite beschreibt, wie bei einem Wechsel auf das WEBSALE Shopsystem (oder bei einem Versionswechsel innerhalb von WEBSALE) mit bestehenden Daten umgegangen wird. Im Fokus stehen: * Daten, die tatsächlich migriert werden (z. B. Bewertungen, Bestellungen, Merklisten, Gutscheine), und * Daten, die über Schnittstellen von Drittsystemen (z. B. ERP/Warenwirtschaft) an WEBSALE geliefert werden (z. B. Produkte, Kategorien, Kundenstammdaten). Nicht betrachtet werden hier die grafische und funktionale Migration von Templates und Layouts. *** ## Allgemein Für alle Datenbereiche sollten im Prinzip die gleichen Fragen gestellt werden: * Liegen die Daten in einem führenden System (z. B. ERP) vor oder im bisherigen Shopsystem? * Gibt es Schnittstellen, über die die Daten künftig an WEBSALE übergeben werden sollen? * Ist ein Export der bestehenden Daten möglich (z. B. CSV, Datenbankdump, API)? * Passen die vorhandenen Datenstrukturen zu den Felddefinitionen des WEBSALE Shopsystems oder ist eine Konvertierung notwendig? ## Datenbereiche im Detail ### Schnittstellen In vielen Projekten erfolgt der Datenaustausch bereits über automatisierte Schnittstellen. Daher ist die Betrachtung der Schnittstellen oft der einfachste und wichtigste erste Schritt in der Datenmigration. Werden im bisherigen Shopsystem bereits Schnittstellen zum Import und Export von Daten genutzt (z. B. zu ERP-/Warenwirtschaftssystemen, PIM, CRM, Payment- oder Versanddienstleistern), bleiben diese externen Systeme in der Regel auch nach dem Wechsel auf WEBSALE führend. Im Rahmen der Migration müssen diese Systeme an die Schnittstellen des WEBSALE Shops angebunden werden. Im Vordergrund stehen dabei: * Zuordnung der bisherigen Endpunkte und Formate zu den WEBSALE Schnittstellen * Anpassung von Formaten, Feldern und Protokollen (Mapping) * technische Tests der Datenübertragungen für Import und Export Alle Informationen zu den Schnittstellen, die der WEBSALE Shop zur Verfügung stellt, finden sich in der [Schnittstellen- und API-Dokumentation](/schnittstellen). Werden bestimmte Daten bisher noch nicht automatisiert übertragen (z. B. regelmäßiger manueller CSV-Import), kann im Zuge der Migration geprüft werden, ob hierfür zusätzliche Schnittstellen eingerichtet werden sollen. In diesem Zusammenhang ist festzulegen, welche Partei die Implementierung übernimmt (z. B. ERP-Hersteller, betreuende Agentur oder interne IT). ### Produkte & Kategorien Für Produkte und Kategorien gibt es typischerweise zwei Szenarien: #### ERP-/PIM-geführt Produkte und Kategorien werden in einem ERP-, Warenwirtschafts- oder PIM-System gepflegt und per Schnittstelle an den Shop übergeben. Bei der Umstellung auf WEBSALE steht daher die Anbindung bzw. Anpassung der Schnittstellen im Vordergrund (siehe Abschnitt „[Schnittstellen](#2-1-schnittstellen)“). Eine separate einmalige Datenmigration ist in diesem Fall meist nicht erforderlich, da die Daten weiterhin laufend aus dem führenden System geliefert werden. #### Shop-geführt Produkte und Kategorien wurden bisher direkt im bisherigen Shopsystem gepflegt und nicht über Schnittstellen aus einem ERP/PIM übernommen. In diesem Fall müssen die Daten aus dem bisherigen Shopsystem exportiert, bei Bedarf in das WEBSALE Format konvertiert und anschließend in den WEBSALE Shop importiert werden. Dabei ist insbesondere das Feldmapping, also die Zuordnung der Felder des bisherigen Shopsystems zu den Feldern im WEBSALE Datenmodell, zu berücksichtigen. Die Zuordnung erfolgt im Konfigurationsknoten `content.usedFields` (siehe Abschnitt „[Konfiguration des Shops](https://websaleag-44ee7ea6.mintlify.app/konfiguration/content-katalog-kategorien-produkte#12-content-usedfields-zuordnung-benutzerdefinierter-felder)“). ### Kundendaten Kundendaten umfassen z. B. Stammdaten (Name, Adress- und Kontaktdaten), Liefer- und Rechnungsadressen, bonitätsrelevante Hinweise, erlaubte bzw. gesperrte Zahlungsarten, Kundengruppen, kundenspezifische Sortimente, kundenindividuelle Preise und Rabattstaffeln sowie weitere Konditionen. Für Kundendaten gibt es typischerweise zwei Szenarien: #### ERP-/CRM-geführt Kundendaten und Konditionen werden in einem ERP-, Warenwirtschafts- oder CRM-System gepflegt und per Schnittstelle an den Shop übergeben. Bei der Umstellung auf WEBSALE steht daher die Anbindung bzw. Anpassung der Schnittstellen im Vordergrund (siehe Abschnitt „[Schnittstellen](#2-1-schnittstellen)“). Kundenabhängige Einstellungen wie zulässige Zahlungsarten, Preislisten, Rabatte, Sortimentsbeschränkungen und Bonitätshinweise bleiben im führenden System und werden von dort an den WEBSALE Shop übermittelt. Eine separate einmalige Datenmigration ist in diesem Szenario meist nur eingeschränkt erforderlich, da die Daten weiterhin laufend aus dem führenden System geliefert werden. #### Shop-geführt Kundendaten und kundenspezifische Konditionen wurden bisher direkt im bisherigen Shopsystem gepflegt und nicht über Schnittstellen aus einem ERP-/CRM-System übernommen. In diesem Fall müssen die relevanten Daten (Stammdaten, Statusinformationen, Zahlungsartenfreigaben/-sperren, kundenspezifische Preise, Sortimentszuordnungen usw.) aus dem bisherigen Shopsystem exportiert, bei Bedarf in das WEBSALE-Format konvertiert und anschließend in den WEBSALE Shop importiert werden. Dabei ist sicherzustellen, dass die Zuordnung zu Kundengruppen, Preislisten, Zahlungsarten und ggf. kundenspezifischen Sortimenten korrekt im WEBSALE Shop abgebildet wird. ### Kundenlogins & Passwörter Kundenlogins bestehen im Wesentlichen aus der Kombination aus Zugangsdaten (z. B. E-Mail-Adresse oder Kundennummer) und Passwort. Aus Datenschutz- und Sicherheitsgründen werden Passwörter im WEBSALE Shop niemals im Klartext gespeichert, sondern ausschließlich in Form kryptographischer Hashwerte. Für die Migration von Kundenlogins ergeben sich im Wesentlichen zwei Szenarien: #### Passwort-Hashes können übernommen werden Im bisherigen Shopsystem werden Passwörter ebenfalls nicht im Klartext, sondern gehasht gespeichert und die verwendeten Hashverfahren sowie die benötigten technischen Informationen (z. B. Salt, Parameter) sind bekannt bzw. exportierbar.\ In diesem Fall ist es möglich, die bestehenden Passwort-Hashes datenschutzkonform zu übernehmen und in das WEBSALE-System zu überführen. So können Kunden nach dem Systemwechsel ihre gewohnten Zugangsdaten weiterverwenden und sich ohne erneute Passwortvergabe im WEBSALE Shop anmelden. #### Passwort-Übernahme ist nicht möglich Ist eine technische Übernahme der bisherigen Passwort-Hashes nicht möglich (z. B. aufgrund proprietärer oder unbekannter Verfahren oder fehlender Zugriffsmöglichkeiten), werden zwar die Kundenkonten in den WEBSALE Shop übernommen, jedoch ohne das bisherige Passwort. In diesem Fall übernimmt der WEBSALE Shop die Benutzerführung, damit Kunden ihr Passwort einfach neu vergeben können, z. B. über: * eine gezielte Aufforderung zur Passwortneuvergabe beim ersten Login-Versuch und * die übliche „Passwort vergessen“-Funktion mit E-Mail-Link. In keinem Szenario werden Passwörter im Klartext zwischen Systemen übertragen oder in Dateien exportiert. ### Bestellhistorie im Kundenkonto Dieser Abschnitt bezieht sich auf die Anzeige von Bestellungen im Kundenkonto (Bestellhistorie, Bestellstatus, Detailansicht der Aufträge) aus Sicht des Kunden. Er beschreibt nicht die technische Übergabe neuer Bestellungen aus dem Shop an ein ERP-/Warenwirtschaftssystem zur weiteren Verarbeitung, sondern die Anbindung bzw. Migration der Daten, die im Shop für die Bestellübersicht genutzt werden. Für die Bestellhistorie im Kundenkonto gibt es typischerweise zwei Szenarien: #### ERP-/Warenwirtschaft-geführt Bestellungen werden zentral in einem ERP- bzw. Warenwirtschaftssystem geführt. Der Shop nutzt in diesem Fall eine Anbindung, die Bestelldaten und Bestellstatus aus dem ERP zur Anzeige im Kundenkonto bereitstellt. Dadurch können im WEBSALE Shop nicht nur Bestellungen angezeigt werden, die über den Online-Shop ausgelöst wurden, sondern auch Bestellungen, die über andere Kanäle (z. B. Telefon, Katalog/Print, Filiale) erfasst wurden. Bei der Umstellung auf WEBSALE steht in diesem Szenario die Anbindung bzw. Anpassung dieser Order-Management-/Anzeige-Schnittstelle im Vordergrund (siehe Abschnitt „[Schnittstellen](#2-1-schnittstellen)“). Die bestehende Anbindung kann in der Regel weiterverwendet bzw. auf die WEBSALE Schnittstellen umgestellt werden. #### Shop-geführt Besteht keine Anbindung für die Anzeige von Bestellungen aus einem ERP-/Warenwirtschaftssystem, werden Bestellungen im Kundenkonto in der Regel direkt aus der Datenbank des bisherigen Shopsystems angezeigt. In diesem Fall müssen die Bestellungen aus dem bisherigen Shopsystem exportiert, bei Bedarf in das WEBSALE-Format konvertiert und anschließend in den WEBSALE Shop importiert werden. Für eine saubere Migration sind insbesondere folgende Informationen relevant: * eindeutige Kundenkennung (UserIndex), * Bestellnummer und Bestelldatum, * Bestellstatus, * Zahlart und Versandart, * Bestellpositionen (Artikel, Menge, Preise). Optional können zusätzlich z. B. Versandinformationen (Trackingcodes), interne Hinweise oder Kommentartexte übernommen werden, sofern sie im WEBSALE Datenmodell abbildbar sind. Je nach Projekt kann zudem entschieden werden, ob die vollständige Historie oder nur Bestellungen ab einem bestimmten Stichtag übernommen werden sollen. ### Produkt- & Kundenbewertungen Produkt- und Kundenbewertungen werden in der Regel nicht in ERP-, Warenwirtschafts- oder PIM-Systemen geführt, sondern über eigene Bewertungsfunktionen des Shopsystems oder über spezialisierte Drittanbietersysteme (z. B. eKomi, Trusted Shops, Trustpilot). Die Bewertungen werden dabei üblicherweise über den Produktindex dem jeweiligen Produkt zugeordnet. Für die Migration und weitere Nutzung von Bewertungen gibt es typischerweise zwei Szenarien: #### Bewertungen über externe Dienstleister Werden Bewertungen von einem externen Dienstleister verwaltet, verbleiben die eigentlichen Bewertungsdaten in der Regel beim Dienstleister. Im Rahmen der Umstellung auf WEBSALE sind dann vor allem folgende Punkte relevant: * Einbindung der benötigten Widgets, Skripte oder Plugins des Dienstleisters in die Templates der WEBSALE Storefront, * Sicherstellung, dass die Zuordnung der Bewertungen zu Produkten weiterhin funktioniert (z. B. über Produkt-ID, SKU oder URL), * Übernahme oder Neuimplementierung der Prozesse für Bewertungsanfragen, z. B. automatische Versendung von Bewertungsaufforderungen nach einer Bestellung (API-Aufruf, Exportdatei, Webhook o. Ä.). Die eigentliche Datenmigration der Bewertungen erfolgt in diesem Szenario in der Regel nicht im WEBSALE Shop, sondern über die bestehende Datenbasis beim externen Dienstleister. Nach erfolgreicher Integration werden die Bewertungen automatisch im neuen WEBSALE Shop angezeigt. #### Bewertungen im bisherigen Shopsystem (shop-eigenes Bewertungssystem) Wurden Produkt- und ggf. Kundenbewertungen bisher direkt im bisherigen Shopsystem gespeichert, können diese in das WEBSALE System übernommen werden, sofern ein geeigneter Export möglich ist. In diesem Fall gilt: * Export der Bewertungen aus dem bisherigen Shopsystem (z. B. Produktkennzeichnung, Bewertungswert, Bewertungstext, Datum, Freigabestatus, optional Kunden- oder Bestellbezug), * Konvertierung in das WEBSALE-Format und Zuordnung zu den entsprechenden Produkten im WEBSALE Shop, * Import der Bewertungen in das WEBSALE Bewertungssystem. WEBSALE ist in der Lage, Bewertungen Produkten, Bestellungen und Kunden zuzuordnen. Werden im Rahmen der Migration auch Kunden- und Bestellreferenzen mit übergeben, können Kundinnen und Kunden im Kundenkonto weiterhin eine Übersicht über ihre eigenen Bewertungen bzw. bewerteten Bestellungen erhalten. ### Merklisten & Wunschlisten Merklisten bzw. Wunschlisten sind für viele Kunden ein wichtiger Bestandteil des Einkaufserlebnisses. Sie ermöglichen es, Produkte über einen längeren Zeitraum zu beobachten, zu vergleichen und zu einem späteren Zeitpunkt zu bestellen. Gerade bei wiederkehrenden Bestellungen oder höherpreisigen Artikeln tragen Merklisten dazu bei, dass Kundenbeziehungen stabil bleiben und Kaufentscheidungen vorbereitet werden. Merk- und Wunschlisten werden in der Regel nicht in ERP-, CRM- oder Warenwirtschaftssystemen geführt, sondern direkt im jeweiligen Shopsystem gespeichert. Für die Migration bedeutet dies in der Praxis: * Die Einträge der Merk- bzw. Wunschlisten müssen aus dem bisherigen Shopsystem exportiert werden. * Die Daten (insbesondere Zuordnung zu Kundenkonten und Produkten) müssen bei Bedarf in das WEBSALE-Format konvertiert werden. Wichtig sind dabei vor allem: * eine eindeutige Kundenkennung, * eine eindeutige Produktreferenz (z. B. Produktindex). * Anschließend werden die konvertierten Daten in den WEBSALE Shop importiert. So wird sichergestellt, dass Kunden nach der Umstellung ihre bestehenden Merk- bzw. Wunschlisten im neuen WEBSALE Shop wieder vorfinden und nahtlos weiter nutzen können. ### Newsletter-Abonnements Newsletter-Abonnements werden entweder in einem externen Newslettersystem oder direkt im bisherigen Shopsystem verwaltet. #### Externe Newsletter-Systeme Werden Newsletter-Abonnements bereits über ein externes System (z. B. Inxmail, CleverReach oder vergleichbare Anbieter) verwaltet, verbleiben die Verteiler und Abonnentendaten in der Regel in diesem System. Bei der Umstellung auf WEBSALE sind dann folgende Punkte relevant: * Einbindung bzw. Anpassung der bestehenden Integration des Newsletter-Anbieters im WEBSALE Shop (Formulare, An- und Abmeldeprozesse, ggf. Tracking-Parameter), * Sicherstellung, dass Anmeldungen und Abmeldungen weiterhin korrekt an den externen Anbieter übergeben werden (z. B. per API, Formular-POST, Webhook). Eine eigentliche Datenmigration der Abonnentendaten in den WEBSALE Shop ist in diesem Szenario üblicherweise nicht erforderlich, da die Verwaltung der Verteiler im externen System verbleibt. #### Shop-eigenes Newslettersystem Wurden Newsletter-Abonnements bisher direkt im bisherigen Shopsystem verwaltet, können diese Daten in das WEBSALE Newslettersystem übernommen werden, sofern ein geeigneter Export möglich ist. Typischer Ablauf: * Export der Abonnentendaten aus dem bisherigen Shopsystem (z. B. E-Mail-Adresse, optional Name, Anmeldedatum, Opt-In-Status, Sprache, Interessen/Listen), * Konvertierung in das WEBSALE-Format, * Import in das WEBSALE Newslettersystem. Je nach rechtlicher Bewertung und eingesetztem Verfahren ist es möglich, die bestehende Einwilligung (Opt-In) beizubehalten. Optional kann im Zuge der Migration für zusätzliche Rechtssicherheit eine erneute Bestätigung (z. B. erneutes Double-Opt-In) ausgelöst werden, bei der alle importierten Adressen noch einmal um Bestätigung gebeten werden. ### Gutscheine Gutscheine sind ein wichtiges Marketing- und Serviceinstrument. Nach einem Systemwechsel sollte sichergestellt sein, dass Gutscheine, die sich noch im Umlauf befinden, auch im neuen System weiterhin eingelöst werden können. Für die Verwaltung von Gutscheinen gibt es typischerweise zwei Szenarien: #### ERP-/Warenwirtschaft-geführt Werden Gutscheine in einem ERP- bzw. Warenwirtschaftssystem erstellt und verwaltet (z. B. Anlage, Gültigkeitszeitraum, Restwerte, Einlösestatus), ist dieses System führend. Bei der Umstellung auf WEBSALE muss die bestehende Gutscheinlogik weiterhin über das Warenwirtschaftssystem bereitgestellt werden. Dazu ist die Anbindung bzw. Anpassung der entsprechenden Schnittstellen erforderlich (siehe Abschnitt „[Schnittstellen](#2-1-schnittstellen)“). Auf diese Weise ist gewährleistet, dass: * bestehende Gutscheincodes weiterhin erkannt werden, * Gültigkeit und Restwerte korrekt geprüft werden und * Einlösungen im ERP-/Warenwirtschaftssystem verbucht werden. #### Shop-geführt Werden Gutscheine direkt im bisherigen Shopsystem erstellt und verwaltet, liegen alle relevanten Gutscheininformationen in der Shop-Datenbank. In diesem Fall müssen die bestehenden Gutscheine im Rahmen der Migration: * aus dem bisherigen Shopsystem exportiert, * bei Bedarf in das WEBSALE-Format konvertiert und * anschließend in den WEBSALE Shop importiert werden. Für die Migration sind insbesondere folgende Daten relevant: * Gutscheincode, * Typ und Wert (z. B. Betrag, Prozent), * Restwert (bei Wertgutscheinen), * Gültigkeitszeitraum, * Einlösestatus, * ggf. Kundenzuordnung oder Einschränkungen (z. B. bestimmte Kundengruppen, Sortimente). Je nach Projekt kann festgelegt werden, ob alle historischen Gutscheine übernommen werden oder nur aktuell gültige bzw. noch nicht eingelöste Gutscheine. ### Bonuspunkte & Guthaben Bonuspunkte- und Prämiensysteme, Kundenkarten-Guthaben oder vergleichbare Modelle ermöglichen es Kunden, bei Bestellungen Punkte oder Geldwerte zu sammeln und später als Rabatt oder Zahlungsmittel einzulösen. Bei einem Systemwechsel sollte sichergestellt werden, dass bereits aufgebaute Punktestände und Guthaben nicht verloren gehen und nach der Umstellung weiter genutzt werden können. Für Bonuspunkte und Guthaben gibt es typischerweise zwei Szenarien: #### ERP-/Warenwirtschaft-geführt Werden Bonuspunkte, Prämien und Guthaben in einem ERP- oder Warenwirtschaftssystem geführt, ist dieses System für die Berechnung und Verwaltung der Werte verantwortlich (Sammeln, Einlösen, Restwerte, Gültigkeit). Der Shop greift in diesem Fall über Schnittstellen auf diese Informationen zu, etwa um: * aktuelle Punktestände oder Guthaben im Kundenkonto anzuzeigen, * bei Bestellungen das Sammeln neuer Punkte anzustoßen oder * eingelöste Punkte und Guthaben an das ERP/Warenwirtschaftssystem zurückzumelden. Bei der Umstellung auf WEBSALE müssen diese Systeme an die Schnittstellen des WEBSALE Shops angebunden werden (siehe Abschnitt „[Schnittstellen](#2-1-schnittstellen)“). Konfigurationen wie Umrechnungsfaktoren (z. B. Euro zu Punkten), mögliche Einlösekombinationen oder Bedingungen (Mindestbestellwert, bestimmte Kundengruppen, Sortimente) können – sofern im WEBSALE Shop abgebildet – über die entsprechenden Shopeinstellungen konfiguriert werden, damit Kunden wie bisher Punkte und Guthaben sammeln und einlösen können. #### Shop-geführt Werden Bonuspunkte, Prämien und Guthaben ausschließlich im bisherigen Shopsystem geführt, liegen die relevanten Stände und Historien in der Shop-Datenbank. In diesem Fall müssen die Daten: * aus dem bisherigen Shopsystem exportiert, * bei Bedarf in das WEBSALE-Format konvertiert und * anschließend in den WEBSALE Shop importiert werden. Wesentliche Informationen sind dabei insbesondere: * eindeutige Kundenkennung (z. B. Kunden-ID, E-Mail), * aktueller Punktestand bzw. Guthabenwert, * ggf. Gültigkeitszeiträume oder Ablaufdaten, * optional Historieninformationen (z. B. wann Punkte gesammelt oder eingelöst wurden). Nach dem Import müssen im WEBSALE Shop die passenden Einstellungen für das Bonus- bzw. Prämiensystem konfiguriert werden (z. B. Sammelregeln, Einlösebedingungen, Umrechnung von Punkten in Währung), damit Kunden ihre bestehenden Punktestände und Guthaben im neuen System wie gewohnt weiter nutzen und weiter aufbauen können. ### Produkt-Abonnements Produkt-Abonnements (z. B. regelmäßige Futterlieferungen für Haustiere, Lieferungen von Supplements oder anderen Verbrauchsartikeln) sollen auch nach einem Systemwechsel zuverlässig weiterlaufen. Ziel der Migration ist, dass bestehende Abos erhalten bleiben und die zugehörigen Bestellungen weiterhin automatisch erzeugt und ausgeliefert werden. Für Produkt-Abonnements gibt es typischerweise zwei Szenarien: #### ERP-/Warenwirtschaft-geführt Werden Produkt-Abonnements in einem ERP- bzw. Warenwirtschaftssystem verwaltet (inkl. Lieferintervallen, nächstem Liefertermin, erlaubten Zahlungsarten, Laufzeiten, Pausenfunktionen usw.), ist dieses System führend. Der Shop dient in diesem Fall hauptsächlich zur Anzeige und zur Erfassung von Änderungen durch den Kunden. Bei der Umstellung auf WEBSALE müssen diese Abonnementdaten weiterhin über die entsprechenden Schnittstellen an den WEBSALE Shop übergeben werden (siehe Abschnitt „[Schnittstellen](#2-1-schnittstellen)“). Damit wird sichergestellt, dass: * bestehende Abonnements im Kundenkonto angezeigt werden, * automatische Folgebestellungen wie gewohnt ausgelöst werden und * Änderungen am Abo (z. B. Intervallanpassung, Pause, Kündigung) korrekt verarbeitet werden. #### Shop-geführt Werden Produkt-Abonnements direkt im bisherigen Shopsystem geführt, liegen die relevanten Informationen (z. B. Kunde, Produkt, Lieferintervall, nächster Liefertermin, Zahlungsart, Status, ggf. Pauseninformationen) in der Shop-Datenbank. In diesem Fall müssen diese Daten: * aus dem bisherigen Shopsystem exportiert, * bei Bedarf in das WEBSALE-Format konvertiert und * anschließend in den WEBSALE Shop importiert werden. Zusätzlich müssen im WEBSALE Shop die Einstellungen für: * verfügbare Lieferintervalle, * erlaubte Zahlungsarten für Abonnements, * Funktionen wie Pausieren, Reaktivieren oder Beenden von Abos entsprechend konfiguriert werden, damit die Abonnementlogik im neuen System funktionsfähig bleibt. Wichtig: Für eine fehlerfreie Fortführung der Produkt-Abonnements muss sichergestellt sein, dass die zugehörigen Produkte und Kundendaten ebenfalls korrekt in den WEBSALE Shop übernommen wurden und die Zuordnung (z. B. über Produkt-IDs und Kundenkennungen) weiterhin eindeutig möglich ist. ### URLs, URL-Strukturen & Weiterleitungen URLs, interne Verlinkung und Weiterleitungen gehören zu den sensibelsten Bereichen bei der Umstellung eines Shopsystems. Fehler in diesem Bereich können sich direkt auf Sichtbarkeit in Suchmaschinen, auf Kampagnenlinks und auf gespeicherte Lesezeichen der Kunden auswirken. WEBSALE stellt deshalb umfangreiche Funktionen zur Verfügung, um bestehende URL-Strukturen weitgehend beizubehalten und Weiterleitungen kontrolliert zu steuern. #### URL-Struktur / URL-Schema Um unnötige Weiterleitungen zu vermeiden, bietet der WEBSALE Shop eine flexible URL-Konfiguration. Damit können URL-Strukturen (URL-Schemata) für SEO-relevante Seiten so definiert werden, dass sie den bisherigen Strukturen entsprechen, z. B. für: * Produktseiten * Kategorieseiten * Inhalts- und Content-Seiten (z. B. „Über uns“, Landingpages) Ziel ist, dass sich die URL eines Produkts oder einer Kategorie durch den Systemwechsel idealerweise nicht ändert. Die URL zu einem Produkt kann also im neuen WEBSALE Shop die gleiche sein wie im bisherigen Shopsystem. #### Kurzadressen & Kampagnen-URLs Viele Shops nutzen spezielle Kurzadressen bzw. Kampagnen-URLs, um Landingpages für Marketingmaßnahmen, Newsletter, Social-Media-Posts oder Printkampagnen anzusteuern. Diese Kurzadressen können im WEBSALE Shop ebenfalls abgebildet werden: * Bestehende Kurz- oder Kampagnen-URLs aus dem bisherigen Shopsystem können, sofern sie bekannt bzw. exportierbar sind, übernommen und im WEBSALE Shop eingerichtet werden. * Alternativ können diese URLs über den Redirect-Service des WEBSALE Shops auf die entsprechenden Zielseiten weitergeleitet werden. So bleiben Kampagnenlinks auch nach dem Systemwechsel funktionsfähig. #### Bestehende Weiterleitungen aus dem bisherigen Shopsystem Viele Shopsysteme verfügen über eigene Weiterleitungslogiken, z. B. für: * ausgelistete oder ersetzte Produkte („continued products“), * entfallene Kategorien, * strukturbedingte URL-Änderungen. WEBSALE verfügt selbst über ein eigenes, ausgereiftes Weiterleitungskonzept für Produkte und Kategorien. Produkte bzw. Kategorien, die nicht mehr verfügbar sind, können automatisch auf geeignete Ziele weitergeleitet werden, z. B. auf: * Nachfolge- oder Ersatzprodukte, * übergeordnete Kategorien, * definierte Zielseiten. Sind im bisherigen Shopsystem bereits Weiterleitungen für solche Fälle hinterlegt und können diese Informationen exportiert werden (z. B. in Form von „alte URL → neue URL“-Listen), können diese Daten im Rahmen der Migration übernommen und im WEBSALE Shop abgebildet werden. Damit wird ermöglicht, dass bereits eingerichtete Weiterleitungen auch nach dem Systemwechsel weiterhin greifen. Ein deutlicher Einbruch in den Suchmaschinen muss bei sauberer Planung und Umsetzung daher nicht befürchtet werden. #### Weiterleitungskonzept im WEBSALE Shop (Redirect-Service) Unabhängig von eventuell übernommenen Alt-Weiterleitungen greift mit der Inbetriebnahme des WEBSALE Shops das eigene Weiterleitungskonzept des Systems. Wesentliche Bestandteile sind: * Automatische Weiterleitungen für Produkte und Kategorien, die im System als ersetzt, verschoben oder entfernt gekennzeichnet werden. * Ein Redirect-Service, mit dem gezielt individuelle Weiterleitungen konfiguriert werden können, z. B.: * 301-Weiterleitungen von alten URLs auf neue Zielseiten (Produkte, Kategorien, Content-Seiten), * gezielte Weiterleitungen auf eine definierte Landingpage, * Weiterleitungen auf eine 404-Seite, wenn Inhalte bewusst nicht mehr angeboten werden sollen. Für URLs, die nicht eindeutig zugeordnet werden können, kann ein generisches Weiterleitungsverhalten konfiguriert werden (z. B. 301 auf eine Übersichtsseite oder 404 mit sinnvoll gestalteter Fehlerseite). Dadurch lassen sich unklare Alt-Links auffangen und gezielt steuern. #### SEO-Begleitung beim Systemwechsel Aufgrund der Bedeutung von URLs, Weiterleitungen und SEO-Einstellungen wird dringend empfohlen, den Systemwechsel von einem SEO-Spezialisten begleiten zu lassen. Diese Person kann z. B.: * das URL-Schema im WEBSALE Shop mitplanen, * eine Liste besonders wichtiger URLs aus dem bisherigen Shopsystem erstellen und deren Abbildung bzw. Weiterleitung prüfen, * über das Admin Interface Weiterleitungen (Redirects) und URL-Anpassungen konfigurieren, * weitere SEO-Einstellungen im WEBSALE Shop vornehmen, z. B.: * Konfiguration von Meta-Daten (Title, Description), * Pflege von SEO-relevanten Schemata und Strukturen, * Einrichtung und Aktualisierung von Sitemaps. So wird sichergestellt, dass der Systemwechsel nicht nur funktional gelingt, sondern auch aus SEO-Sicht sauber vorbereitet und umgesetzt wird. ### Tracking-Informationen & Analysen Unter Tracking-Informationen und Analysen fallen z. B. Seitenaufrufe, Klicks, Events, Conversion-Tracking, Funnel-Auswertungen und vergleichbare Messungen des Nutzerverhaltens. In der Praxis werden diese Daten häufig über externe Tracking- und Analyse-Dienste verarbeitet, z. B. Google Analytics / GA4, Matomo, econda oder vergleichbare Systeme. #### Externe Tracking- und Analyse-Systeme Für diese Systeme werden im Shop in der Regel: * Tracking-Snippets, * Tag-Manager-Container (z. B. Google Tag Manager), * oder individuelle Skripte und Events eingebunden, die bestimmte Aktionen, Zustände und Ereignisse (z. B. Seitenaufrufe, Warenkorb-Events, Bestellabschluss) an den jeweiligen Dienst übergeben. Egal, ob der WEBSALE Shop über die Template-Engine oder über die Storefront-API aufgebaut ist:\ Der WEBSALE Shop kann die für die Tracking-Snippets benötigten Informationen (z. B. Produktdaten, Bestellwerte, Kundenzustände, DataLayer-Informationen) bereitstellen, sodass die bestehenden Tracking-Pipelines weiter befüllt werden können. Bei der Umstellung auf WEBSALE geht es daher insbesondere um: * Übernahme bzw. Neueinbindung der vorhandenen Tracking-IDs, Container-IDs und Snippets, * Abbildung der bisher genutzten Events und Parameter im neuen Shop (z. B. via DataLayer oder direkte Übergabe), * Funktionsprüfung der Integration (Testbestellungen, Test-Events). Die historischen Trackingdaten verbleiben im jeweiligen externen System (z. B. Google Analytics, Matomo) und werden nicht in den WEBSALE Shop migriert. Nach dem Go-Live werden neue Daten in denselben oder neuen Properties/Konten erfasst und können dort ausgewertet werden. #### Shop-eigene Statistiken Viele Shopsysteme stellen zusätzlich interne Statistiken und Auswertungen zur Verfügung, z. B.: * Auswertungen zum Nutzungsverhalten, * Kennzahlen zu Produkten und Kategorien, * Bestell- und Umsatzstatistiken. Diese intern im bisherigen Shopsystem erzeugten Statistiken können nicht in das WEBSALE Statistiksystem übernommen oder eingespielt werden. Wenn sie diese Daten weiterhin benötigen, sollten die relevanten Berichte und Kennzahlen vor dem Systemwechsel im bisherigen Shopsystem exportiert bzw. gesichert werden (z. B. als CSV oder PDF), um sie bei Bedarf später mit den WEBSALE Statistiken vergleichen zu können. Die Statistiken im WEBSALE Shop starten mit dem Produktivbetrieb des neuen Systems und bauen von diesem Zeitpunkt an eine neue Datenbasis auf. ### Anfragen Formulare (z. B. für Kontaktanfragen, Widerrufe, Rückrufservice, Reklamationen) dienen dazu, Kundenanliegen strukturiert zu erfassen und an die richtigen Stellen weiterzuleiten. In WEBSALE können die benötigten Formulare direkt im System erstellt werden. Die Formularerstellung ist flexibel und ermöglicht unter anderem: * frei definierbare Felder, * Abhängigkeiten zwischen Eingaben (z. B. zusätzliche Felder je nach Auswahl), * Plausibilitätsprüfungen und Validierungen, * Adressprüfungen analog zu Rechnungs- und Lieferadressen. Ausgefüllte Formulare können in WEBSALE: * per E-Mail an definierte Adressen beim Händler gesendet werden, * an externe Systeme (z. B. CRM-Systeme) weitergegeben werden, * direkt im Admin Interface eingesehen und bearbeitet werden. Bei der Bearbeitung im Admin Interface können Anfragen mit Bearbeitungsstatus versehen und dokumentiert werden, ohne dass dafür ein externes System erforderlich ist. Anfragen, die bereits im bisherigen Shopsystem eingegangen sind und sich zum Zeitpunkt der Umstellung noch in Bearbeitung befinden, werden nicht nach WEBSALE migriert. Üblicherweise werden diese offenen Anfragen weiterhin im bisherigen Shopsystem beantwortet und dort abgeschlossen (inklusive Statusänderungen, interner Notizen usw.). Neue Anfragen nach dem Go-Live werden dann über die in WEBSALE eingerichteten Formulare erfasst und über die neuen Prozesse verarbeitet. ### Verfügbarkeitsalarame resp. Verfügbarkeits-Benachrichtigungen WEBSALE bietet die Möglichkeit, für aktuell nicht verfügbare Produkte Verfügbarkeitsalarme bzw. Verfügbarkeits-Benachrichtigungen zu hinterlegen. Kunden können sich eintragen, wenn ein Produkt ausverkauft ist, und werden automatisch informiert, sobald der Artikel wieder verfügbar ist. Die dafür benötigten Informationen (z. B. Produktreferenz, Kontaktangabe, Zeitpunkt der Registrierung) werden im WEBSALE Shop in der Datenbank gespeichert und bei Bestandsänderungen ausgewertet. Stellt das bisherige Shopsystem eine vergleichbare Funktion zur Verfügung und können die dort hinterlegten Verfügbarkeitsalarme exportiert werden, können diese Daten: * aus dem bisherigen Shopsystem exportiert, * bei Bedarf in das WEBSALE-Format konvertiert und * anschließend in den WEBSALE Shop importiert werden. Wesentlich ist dabei, dass: * eine eindeutige Zuordnung zum jeweiligen Produkt (z. B. Produktindex, Artikelnummer, StoreID etc.) möglich ist und * nur offene, noch nicht ausgelöste Benachrichtigungen übernommen werden. Im WEBSALE Shop kann konfiguriert werden, * ab wann ein Produkt wieder als „verfügbar“ gilt (z. B. ab einer bestimmten Bestandsmenge), * unter welchen Bedingungen eine Verfügbarkeitsbenachrichtigung ausgelöst wird und * in welcher Form die Benachrichtigung erfolgen soll. So wird sichergestellt, dass bestehende Verfügbarkeitsalarme beim Systemwechsel nicht verloren gehen und Kunden auch nach dem Umzug auf das WEBSALE Shopsystem automatisch informiert werden, sobald ihre ausgewählten Produkte wieder verfügbar sind. ### Inhalte & Content-Seiten Unter Inhalte bzw. Content-Seiten fallen z. B.: * rechtliche Seiten wie Impressum, AGB, Datenschutzerklärung, * Informationsseiten wie „Wir über uns“, FAQ, Service-Seiten, * Landingpages und Kampagnenseiten, * Content-Elemente und Widgets wie Slider auf der Startseite, Teaserflächen, Banner u. ä. Auch für Inhalte gibt es typischerweise zwei Szenarien: #### Externes CMS-geführt Werden Seiten und Content-Elemente bereits über ein externes CMS-System gepflegt und über eine Anbindung im bisherigen Shopsystem ausgespielt, verbleiben die Inhalte in der Regel weiterhin im CMS. Bei der Umstellung auf WEBSALE ist dann vor allem relevant: * die Anbindung des bestehenden CMS an den WEBSALE Shop (z. B. über APIs oder Feed-Formate), * die Anpassung der Templates in WEBSALE, damit die gelieferten Inhalte an den gewünschten Stellen ausgegeben werden, * ggf. die Übernahme bestehender URL-Strukturen für wichtige Content-Seiten (siehe auch SEO-URLs). Eine eigentliche Migration der Inhalte in die Shop-Datenbank ist in diesem Szenario meist nicht notwendig, da das CMS weiterhin führend bleibt. #### Shop-geführt Werden Inhalte direkt im bisherigen Shopsystem gepflegt (z. B. CMS-Funktionen des Shops, statische Seiten, Content-Widgets), liegen die Inhalte in der Shop-Datenbank oder in shop-spezifischen Strukturen vor. In diesem Fall sollte geprüft werden: * ob ein Export der Inhalte möglich ist, idealerweise in einem strukturierten Format (z. B. JSON), * ob dabei Metadaten wie Seitentyp, Position im Shop, Sprachvarianten, SEO-Informationen (Titel, Beschreibung) mit ausgegeben werden. Sind Exportdaten in einem geeigneten Format vorhanden, können diese Inhalte dem WEBSALE Shop zur Verfügung gestellt, bei Bedarf konvertiert und dann in den WEBSALE Content-Strukturen abgebildet werden. Die Ausgabe erfolgt anschließend über die entsprechenden Templates im gewünschten Layout bzw. Design. Wo kein sinnvoller Export möglich ist oder Inhalte stark redesignet werden sollen, kann im Projekt festgelegt werden, welche Seiten und Inhalte im neuen WEBSALE Shop manuell neu angelegt und inhaltlich aus dem bisherigen System übernommen werden. # Migration WEBSALE V8s -> Neue Version Source: https://dokumentation.websale.de/migration/migration-websale-v8s-neue-version Einstieg in die Migration von WEBSALE V8s auf die neue Version: Bereiche, Hinweise und Migrationshilfen für Konfiguration und Templates im Überblick. Diese Seite und ihre Unterseiten beschäftigen sich ausschließlich mit der Migration von Shops, die von der WEBSALE Version V8s auf die neue Version umgestellt werden. Sie bündeln die dafür relevanten Informationen, Hinweise und Migrationshilfen für die betroffenen Bereiche. ## Übersicht * [Konfiguration-Migration](/migration/migration-websale-v8s-neue-version/konfiguration-migration) — Diese Seite dient als Migrationshilfe für die Konfiguration von Shops, die bisher auf V8s laufen und in die neue Version übernommen werden sollen. Sie unterstützt dabei, bestehende Konfigurationsabschnitte und Einstellungen der bisherigen Konfigurationsdateien den entsprechenden Konfigurationsknoten der neuen Version zuzuordnen, damit der Shop auch nach der Migration identisch oder möglichst vergleichbar konfiguriert werden kann. * [Template-Migration](/migration/migration-websale-v8s-neue-version/template-migration) — Die Template Engine dieser Version unterscheidet sich grundlegend von der bisherigen Implementierung in WEBSALE V8s. Diese Seite soll Agenturen, Template Managern und Entwicklern beim Umstieg unterstützen, indem typische Funktionen und Muster aus V8 den entsprechenden Konzepten dieser Version gegenübergestellt werden. # Konfiguration-Migration Source: https://dokumentation.websale.de/migration/migration-websale-v8s-neue-version/konfiguration-migration Migrationshilfe für die V8s shop.config: Konfigurationsabschnitte alphabetisch den entsprechenden Knoten der neuen WEBSALE-Version zugeordnet. Diese Seite dient als Migrationshilfe für die Konfiguration von Shops, die bisher auf V8s laufen und in die neue Version übernommen werden sollen. Sie unterstützt dabei, bestehende Konfigurationsabschnitte und Einstellungen der bisherigen Konfigurationsdateien den entsprechenden Konfigurationsknoten der neuen Version zuzuordnen, damit der Shop auch nach der Migration identisch oder möglichst vergleichbar konfiguriert werden kann. *** ## Shopkonfiguration shop.config Die folgende Übersicht enthält die Konfigurationsabschnitte der V8s-`shop.config` in alphabetischer Reihenfolge. Eine vollständige Beschreibung aller Abschnitte findet sich in der [V8s-Dokumentation](https://doku.websale.net/index.html?referenz_shopkonfiguration_shop_config.html). Jedem Abschnitt wurde nach Möglichkeit der entsprechende Konfigurationsknoten der neuen Version zugeordnet. So soll die Übersicht dabei unterstützen, bestehende V8s-Konfigurationen in der neuen Version identisch oder fachlich vergleichbar umzusetzen. Fehlen Abschnitte oder einzelne Parameter ohne Zuordnung, hilft unser Support über das Support-Center gern weiter. ### Alphabetische Übersicht der V8s Abschnitte * `` * [checkout.checkout.freeFields](https://websaleag-44ee7ea6.mintlify.app/konfiguration/checkout-bestellablauf#2-checkout-checkout-bestellablauf) * `` * [urls.redirects](https://websaleag-44ee7ea6.mintlify.app/konfiguration/urls-url-webadressen#3-urls-redirects-weiterleitungen-für-fehlerhafte-urls) * `` * Ersatzlos entfallen; jedes Produktdatenfeld kann im Warenkorb angezeigt werden - ohne zusätzliche Konfiguration. * `` * Ersatzlos entfallen; Relaods, Refreshs etc. können ohne Konfiguration auf Basis der [accounts.addressFieldsSettings](https://websaleag-44ee7ea6.mintlify.app/konfiguration/accounts-benutzerkonten#4-accounts-addressfieldssettings-individuelle-adressfelder-einstellungen) direkt im Template hinzugefügt werden * `` * [accounts.addressFieldsSettings](https://websaleag-44ee7ea6.mintlify.app/konfiguration/accounts-benutzerkonten#4-accounts-addressfieldssettings-individuelle-adressfelder-einstellungen) * `` * [accounts.addressFieldsSettings](https://websaleag-44ee7ea6.mintlify.app/konfiguration/accounts-benutzerkonten#4-accounts-addressfieldssettings-individuelle-adressfelder-einstellungen) * `` * [accounts.addressFieldsSettings](https://websaleag-44ee7ea6.mintlify.app/konfiguration/accounts-benutzerkonten#4-accounts-addressfieldssettings-individuelle-adressfelder-einstellungen) * `` * [accounts.addressFieldsSettings](https://websaleag-44ee7ea6.mintlify.app/konfiguration/accounts-benutzerkonten#4-accounts-addressfieldssettings-individuelle-adressfelder-einstellungen) * `` * [accounts.addressField](https://websaleag-44ee7ea6.mintlify.app/konfiguration/accounts-benutzerkonten#5-accounts-addressfield-einzelne-adressfelder-definieren) * [accounts.addressFieldsSettings](https://websaleag-44ee7ea6.mintlify.app/konfiguration/accounts-benutzerkonten#5-accounts-addressfield-einzelne-adressfelder-definieren) * `` * [accounts.addressField](https://websaleag-44ee7ea6.mintlify.app/konfiguration/accounts-benutzerkonten#5-accounts-addressfield-einzelne-adressfelder-definieren) * `` * [general.consentCookieGroup](/konfiguration/general-allgemeine-shopeinstellungen) * [general.consentCookieService](https://websaleag-44ee7ea6.mintlify.app/konfiguration/accounts-benutzerkonten#5-accounts-addressfield-einzelne-adressfelder-definieren) * `` * [general.asse](https://websaleag-44ee7ea6.mintlify.app/konfiguration/general-allgemeine-shopeinstellungen#4-general-asse-schnittstelle-für-asynchronous-server-side-events-asse) * `` * [general.general](https://websaleag-44ee7ea6.mintlify.app/konfiguration/general-allgemeine-shopeinstellungen#10-general-general-allgemeine-basiseinstellungen) * [general.language](https://websaleag-44ee7ea6.mintlify.app/konfiguration/general-allgemeine-shopeinstellungen#11-general-language-sprachdefinitionen) * [general.subshop](https://websaleag-44ee7ea6.mintlify.app/konfiguration/general-allgemeine-shopeinstellungen#18-general-subshop-subshop-definitionen) und [general.subshopView](https://websaleag-44ee7ea6.mintlify.app/konfiguration/general-allgemeine-shopeinstellungen#19-general-subshopview-subshop-konfigurationen) * [general.testMode](https://websaleag-44ee7ea6.mintlify.app/konfiguration/general-allgemeine-shopeinstellungen#20-general-testmode-testmodus) * `` * [basket.basket](https://websaleag-44ee7ea6.mintlify.app/konfiguration/basket-warenkorb#2-basket-basket-einstellungen-für-den-warenkorb) * `` * Noch nicht verfügbar * `` * Ersatzlos entfallen; entsprechende Texte werden direkt im Template oder über Textbausteine gesetzt. * `` * Ersatzlos entfallen; entsprechende Texte werden direkt im Template oder über Textbausteine gesetzt * `` * Ersatzlos entfallen; da die Anzahl von Produkten in einer Kategorie ohne zusätzliche Konfiguration direkt im Template über die Kategoriedaten geladen werden kann, z.B. `$myVariable.productsCount` * `` * [actions.emailUpdate](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto#6-1-actions-emailupdate-e-mail-adresse-ändern) * `` * [finance.currency](https://websaleag-44ee7ea6.mintlify.app/konfiguration/finance-wahrungen-steuern#2-finance-currency-währungen) * `` * [actions.checkoutConfirm](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout#2-3-actions-checkoutconfirm-bestellung-abschließen) * `` bis `` * [accounts.addressField](/konfiguration/accounts-benutzerkonten) * [accounts.addressFieldsSettings](/konfiguration/accounts-benutzerkonten) * `` bis `` * [accounts.addressField](/konfiguration/accounts-benutzerkonten) * [accounts.addressFieldsSettings](/konfiguration/accounts-benutzerkonten) * `` * Konfigurierbar über “SEO-URLs” im Admin Interface oder [PUT seo/urls](https://websaleag-44ee7ea6.mintlify.app/schnittstellen/admin-interface-api/api-referenz-seo-urls#3-8-put-seo/urls) * `` * [actions.accountDelete](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto#2-1-actions-accountdelete-kontolöschung) * `` und `<+Deliverer>` * [checkout.shippingMethod](https://websaleag-44ee7ea6.mintlify.app/konfiguration/checkout-bestellablauf#5-checkout-shippingmethod-versandarten) * `` * [accounts.addressFieldsSettings](https://websaleag-44ee7ea6.mintlify.app/konfiguration/accounts-benutzerkonten#4-accounts-addressfieldssettings-individuelle-adressfelder-einstellungen) * `` * [accounts.addressField](/konfiguration/accounts-benutzerkonten) * [accounts.addressFieldsSettings](/konfiguration/accounts-benutzerkonten) * `` * Ersatzlos entfallen; entsprechende Texte werden direkt im Template oder über Textbausteine gesetzt * `` * Noch nicht verfügbar * `` * Demnächst verfügbar * `` * [security.method](https://websaleag-44ee7ea6.mintlify.app/konfiguration/security-sicherheitsregeln#3-security-method-sensible-daten-verschlüsseln) * `` * [checkout.directOrder](https://websaleag-44ee7ea6.mintlify.app/konfiguration/checkout-bestellablauf#3-checkout-directorder-onlinebestellschein) * [actions.directOrder](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout#4-actions-directorder-direktbestellung) * `` * Ersatzlos entfallen; da es keine festen Templatezuweisungen mehr gibt. * Die An- bzw. Abmeldungen können auf beliebigen Templates über das Modul [\$wsNewsletter](/frontend/referenz/module/wsnewsletter) integriert werden. * Das gilt auch für eine Anmeldung im Bestellprozess oder beim Login. * `` * [actions.newsletter\*](/frontend/referenz/aktionen/newsletter) * `` * Ersatzlos entfallen, da es keine Unterstützung von nativen Anbindungen zu externen Suchdienstleistern gibt. Die Integration erfolgt clientseitig über WebComponents oder Javascript zzgl. Datenfeeds zur Übertragung der Produktdaten. * `` * WEBSALE Search * `` * [messages.emails](https://websaleag-44ee7ea6.mintlify.app/konfiguration/messages-ereignisgesteuerte-e-mails#2-messages-emails-ereignisgesteuerte-e-mails) * `` * Ersatzlos entfallen, da es keine automatisch generierten Schaltflächen-Icons für die Storefront mehr gibt. Schaltflächen können mittels Template Sprache oder Storefront API völlig frei für die Storefront erstellt werden * `` und `<+InputCheck>` * [addressCheck.\*](https://websaleag-44ee7ea6.mintlify.app/konfiguration/validierungs-und-prufservices#1-addresscheck-adressvalidierungen) * [data.checker\*](https://websaleag-44ee7ea6.mintlify.app/konfiguration/validierungs-und-prufservices#2-datachecker-allgemeine-feldvalidierungen) * `<+InputCheck>` `type=zip` → [general.zipCodes](https://websaleag-44ee7ea6.mintlify.app/konfiguration/general-allgemeine-shopeinstellungen#22-general-zipcodes-postleitzahl-prüfungen) * `` * [content.inventory](/konfiguration/content-katalog-kategorien-produkte) * [actions.inventoryReserve](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout#6-actions-inventoryreserve-reservierung-im-warenkorb) * `` * [urls.urls](https://websaleag-44ee7ea6.mintlify.app/konfiguration/urls-url-webadressen#1-urls-grundstruktur) * `` * [b2b.access](https://websaleag-44ee7ea6.mintlify.app/konfiguration/b2b-business-to-business-b2b#2-b2b-access-zutrittsbeschränkungen) * [accounts.accountRestrictions](https://websaleag-44ee7ea6.mintlify.app/konfiguration/accounts-benutzerkonten#3-accounts-accountrestrictions-subshopbeschränkungen-für-benutzerkonten) * [actions.login](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-anmeldung-registrierung#3-actions-login-anmeldung) * [actions.passwordForgotten](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-anmeldung-registrierung#5-actions-passwordforgotten-passwort-vergessen) * [actions.resetPassword](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-anmeldung-registrierung#6-actions-resetpassword-passwort-zurücksetzen) * [actions.login](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-anmeldung-registrierung#3-actions-login-anmeldung) * `` * WEBSALE Search * `` * [actions.accountActivateOptIn](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto#2-5-actions-accountactivateoptin-bestandskundenaktivierung-opt-in-bestätigung) * `` * [actions.accountRegister](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto#2-3-actions-accountregister-benutzer-registrieren) * `` * Je nach Fall [actions.\*](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) * `` * [checkout.checkout](https://websaleag-44ee7ea6.mintlify.app/konfiguration/checkout-bestellablauf#2-checkout-checkout-bestellablauf) * Teilweise [actions.checkoutConfirm](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout#2-3-actions-checkoutconfirm-bestellung-abschließen) * `` * [content.inventory](https://websaleag-44ee7ea6.mintlify.app/konfiguration/content-katalog-kategorien-produkte#8-content-inventory-lagerverwaltung-&-bestandsmeldungen) * `` bis `` * [checkout.checkout](https://websaleag-44ee7ea6.mintlify.app/konfiguration/checkout-bestellablauf#2-checkout-checkout-bestellablauf) * `` * [checkout.checkout](https://websaleag-44ee7ea6.mintlify.app/konfiguration/checkout-bestellablauf#2-checkout-checkout-bestellablauf) * `` * [payment.payment](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen) * [payment.paypalCheckout](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#4-payment-paypalcheckout-paypal-checkout-konfiguration) oder * [payment.computopHosted](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#2-payment-computophosted-computop-hosted-payments) * `` * Wird aktuell noch nicht unterstützt * `` * [payment.payment](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen); bei Offline-Zahlungsarten ist keine weitere Konfiguration erforderlich * Bei Online-Zahlungsarten zusätzlich die passende Provider-Konfiguration, z. B. [payment.paypalCheckout](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#4-payment-paypalcheckout-paypal-checkout-konfiguration) * Bei Stripe wird die Zahlart ebenfalls über `payment.payment` angelegt; die enthaltenen Stripe-Zahlungsmöglichkeiten werden anschließend in der Regel über [payment.stripe](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#6-payment-stripe-stripe-konfiguration) bzw. den Provider bereitgestellt. * `` * Aktuell nur über [payment.stripe](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#6-payment-stripe-stripe-konfiguration) * `` * [payment.payment](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen) * `` und `` bis `` * [payment.payment](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen) * [payment.payment](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen); bei Online-Zahlungsarten zusätzlich die passende Provider-Konfiguration, z. B. [payment.paypalCheckout](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#4-payment-paypalcheckout-paypal-checkout-konfiguration). Bei Stripe wird die Zahlart ebenfalls über [payment.payment](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen) angelegt; die enthaltenen Stripe-Zahlungsmöglichkeiten werden anschließend in der Regel über [payment.stripe](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#6-payment-stripe-stripe-konfiguration) bzw. den Provider bereitgestellt. * ` und ` * [payment.payment](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen); bei Offline-Zahlungsarten ist keine weitere Konfiguration erforderlich. Bei Online-Zahlungsarten zusätzlich die passende Provider-Konfiguration, z. B. [payment.paypalCheckout](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#4-payment-paypalcheckout-paypal-checkout-konfiguration). Bei Stripe wird die Zahlart ebenfalls über `payment.payment` angelegt; die enthaltenen Stripe-Zahlungsmöglichkeiten werden anschließend in der Regel über [payment.stripe](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#6-payment-stripe-stripe-konfiguration) bzw. den Provider bereitgestellt. * `` * Demnächst verfügbar * `` * Sofortüberweisung wird nicht mehr unterstützt * `` * Konfiguration über [payment.payment](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen) und [payment.paypalCheckout](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#4-payment-paypalcheckout-paypal-checkout-konfiguration) oder [payment.computopHosted](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#2-payment-computophosted-computop-hosted-payments) * `` * Aktuell nur über [payment.stripe](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#6-payment-stripe-stripe-konfiguration) * `` * [payment.payment](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen); bei Online-Zahlungsarten zusätzlich die passende Provider-Konfiguration, z. B. [payment.paypalCheckout](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#4-payment-paypalcheckout-paypal-checkout-konfiguration). Bei Stripe wird die Zahlart ebenfalls über [payment.payment](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen) angelegt; die enthaltenen Stripe-Zahlungsmöglichkeiten werden anschließend in der Regel über [payment.stripe](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#6-payment-stripe-stripe-konfiguration) bzw. den Provider bereitgestellt. * `` * Aktuell nur über [payment.stripe](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#6-payment-stripe-stripe-konfiguration) * `` * Giropay wird nicht mehr unterstützt * `` * Paydirekt wird nicht mehr unterstützt * `` * `` * `` * `` * `` * Wird aktuell noch nicht unterstützt * `` * `` * `` * `` * `` * `` * `` * `` * `` * `` * `` * `` * `` * Konfiguration über [payment.payment](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen) und [payment.paypalCheckout](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#4-payment-paypalcheckout-paypal-checkout-konfiguration) * `` * Ersatzlos entfallen, PayPal nur noch über [payment.payment](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen) und [payment.paypalCheckout](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#4-payment-paypalcheckout-paypal-checkout-konfiguration) * `` * Wird aktuell noch nicht unterstützt * `` * Aktuell nur über [payment.stripe](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#6-payment-stripe-stripe-konfiguration) mit der primären Unterstützung von PostFinance Card und PostFinance Pay als Debit-/Zahlungsmittel * `` * [payment.payment](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen) * `` * Demnächst verfügbar * `` * Aktuell nur über [payment.stripe](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#6-payment-stripe-stripe-konfiguration) * ` bis ` * [payment.payment](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen) * `` * [payment.payment](https://websaleag-44ee7ea6.mintlify.app/konfiguration/payment-zahlungsmethoden#3-payment-payment-zahlungsarten-anlegen) * `` * Ersatzlos entfallen, da jedes Template über den Link-Parameter mit `wsFilter=pdf` als PDF gerendert werden kann * `` * [general.numberFormat](https://websaleag-44ee7ea6.mintlify.app/konfiguration/general-allgemeine-shopeinstellungen#12-general-numberformat-zahlen-und-preisformatierung) * `` * Keine Konfiguration mehr, sondern rein über die Templates in dem an die gewünschten Produkte, die man vergleichen möchte über das Modul [\$wsStore](/frontend/referenz/module/wsstore) speichert und dann die Produktfelder mit den [Funktionen](/frontend/referenz/funktionen) `<` `>` bzw `==` vergleicht * `` * WEBSALE search * `` * Wird aktuell noch nicht unterstützt * `` * WEBSALE Search * `` * [actions.accountRegister](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-benutzerkonto#2-3-actions-accountregister-benutzer-registrieren) * `` * Ersatzlos entfallen, da es keine Unterstützung von nativen Anbindungen zu externen Suchdienstleistern gibt. Die Integration erfolgt clientseitig über WebComponents oder Javascript zzgl. Datenfeeds zur Übertragung der Produktdaten * `` * Ersatzlos entfallen; da SSL Standard ist * `` * [actions.checkPasswortStrength](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-anmeldung-registrierung#2-actions-checkpasswortstrength-passwortstärke-resp-passwortsicherheit) * `` * [accounts.autoLogin](https://websaleag-44ee7ea6.mintlify.app/konfiguration/accounts-benutzerkonten#6-accounts-autologin-angemeldet-bleiben) * `` * [seoMetaData.\*](https://websaleag-44ee7ea6.mintlify.app/konfiguration/seometadata-meta-daten-seo-texte#1-seometadata-grundstruktur) * `` * [seoMetaData.\*](https://websaleag-44ee7ea6.mintlify.app/konfiguration/seometadata-meta-daten-seo-texte#1-seometadata-grundstruktur) * `` * [actions.passwordForgotten](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-anmeldung-registrierung#5-actions-passwordforgotten-passwort-vergessen) * [actions.resetPassword](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-anmeldung-registrierung#6-actions-resetpassword-passwort-zurücksetzen) * `` * Über den Service [LogManager (Logs)](/admin-interface/logmanager-logs) im Admin Interface * `` * Über den Service [LogManager (Logs)](/admin-interface/logmanager-logs) im Admin Interface * `` * Überwiegend [actions.\*](/konfiguration/actions-fehlertexte-e-mails) bzw. Template-/Textbaustein-Thema * `` * Ersatzlos entfallen; lediglich die Templates `start.htm`, `category.htm` und `product.htm` sind fest definiert und dürfen nicht umbenannt werden. Alle andere Funktionen dürfen auf jedem beliebigen Template geladen werden * `` * Ersatzlos entfallen; Texte werden direkt im Template oder über Textbausteine gesetzt * `` * [urls.urls](https://websaleag-44ee7ea6.mintlify.app/konfiguration/urls-url-webadressen#4-urls-urls-allgemeine-einstellungen-für-seo-urls) * [urls.redirects](https://websaleag-44ee7ea6.mintlify.app/konfiguration/urls-url-webadressen#3-urls-redirects-weiterleitungen-für-fehlerhafte-urls) * [general.sitemap](https://websaleag-44ee7ea6.mintlify.app/konfiguration/general-allgemeine-shopeinstellungen#17-general-sitemap-aktivierung-von-sitemap) * ``\ ?????? * `` * [finance.taxRates](https://websaleag-44ee7ea6.mintlify.app/konfiguration/finance-wahrungen-steuern#3-finance-taxrates-steuersätze) * [finance.taxRatesAddition](https://websaleag-44ee7ea6.mintlify.app/konfiguration/finance-wahrungen-steuern#4-finance-taxratesaddition-zusatzsteuersätze) * [finance.taxes](https://websaleag-44ee7ea6.mintlify.app/konfiguration/finance-wahrungen-steuern#5-finance-taxes-steuerberechnung) * `` * [accounts.addressField](https://websaleag-44ee7ea6.mintlify.app/konfiguration/accounts-benutzerkonten#4-accounts-addressfieldssettings-individuelle-adressfelder-einstellungen) * bzw. überwiegend [actions.\*](/konfiguration/actions-fehlertexte-e-mails) bzw. Template-/Textbaustein-Thema * `` * [actions.voucherAdd](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout#5-2-actions-voucherdelete-gutschein-löschen) * [actions.voucherDelete](/konfiguration/actions-fehlertexte-e-mails/actions-warenkorb-checkout) * `` * Keine Konfiguration mehr, sondern rein über das Template mit dem Modul [\$wsCookies](/frontend/referenz/module/ws-cookie-browser-cookie) abbildbar * `` * Ersatzlos entfallen; WSP Manager gibt es nicht mehr ## Länder-Liste country.dat * `country.dat` * `deliv_country.dat` * [general.country](https://websaleag-44ee7ea6.mintlify.app/konfiguration/general-allgemeine-shopeinstellungen#6-general-country-länderdefinitionen) ## Titel-Liste title.dat * `title.dat` * [general.title](https://websaleag-44ee7ea6.mintlify.app/konfiguration/general-allgemeine-shopeinstellungen#21-general-title-titel-für-die-anrede) ## Anrede-Liste salutation.dat * `salutation.dat` * [general.salutation](https://websaleag-44ee7ea6.mintlify.app/konfiguration/general-allgemeine-shopeinstellungen#16-general-salutation-anreden) ## Produktbewertung prodrating.config * `prodrating.config` * [actions.productRating\*](https://websaleag-44ee7ea6.mintlify.app/konfiguration/actions-fehlertexte-e-mails/actions-produkte#3-actions-productrating-produktbewertung) # Template-Migration Source: https://dokumentation.websale.de/migration/migration-websale-v8s-neue-version/template-migration Hilfe für den Umstieg von V8-Templates auf die neue Template Engine: typische Funktionen, Module und Muster gegenübergestellt für eine sichere Migration. Die Template Engine dieser Version unterscheidet sich grundlegend von der bisherigen Implementierung in WEBSALE V8s. Diese Seite soll Agenturen, Template Managern und Entwicklern beim Umstieg unterstützen, indem typische Funktionen und Muster aus V8 den entsprechenden Konzepten dieser Version gegenübergestellt werden. Ziel ist es, sich in der neuen Struktur schneller zurechtzufinden und bestehende Implementierungen gezielt zu migrieren, statt jede Stelle „neu zu erfinden“. *** ## Address * Kundenkonto-Informationen werden über das Modul [\$wsAccount](/frontend/referenz/module/wsAccount) geladen * Adressinformationen innerhalb des Bestellablaufes werden zudem über das Modul [\$wsCheckout](/frontend/referenz/module/wscheckout) geladen, z.B. gewählte Lieferadresse, gewählte Rechnungsadresse etc. ## Basics * Vergleich Einzeltag, Schleife, Bereichstag, negativer Bereichstag im Vergleich zu V8: * `~Einzeltag~` → (VX-Pendant ergänzen) * `{@Tag}` → `foreach` * `{Positiver Bereich} … {/Positiver Bereich}` * `{!Negativer Bereich} … {/!Negativer Bereich}` ## Basket * Der Warenkorb wird über das Modul [\$wsBasket](/frontend/referenz/module/wsbasket) geladen ## Breadcrumb * Der Breadcrumb wird über das Modul [\$wsNavigation](/frontend/referenz/module/wsnavigation) geladen ## Category * Kategorien und somit auch die Navigation wird über das Modul [\$wsCategories](/frontend/referenz/module/wscategories) geladen ## DesignControl-Tags * Die Funktionen der DesignControl-Tags stehen über die [Funktionen](/frontend/referenz/funktionen) und [Modifiers](/frontend/referenz/modifiers) zur Verfügung ## Encoding * Zeichensatz geändert von `iso 8859-1` auf `utf-8`. * `iso XXXX-X` wird nicht mehr unterstützt / wurde komplett entfernt. ## Forms * Shop-Aktionen, wie Rechnungsadresse speichern, Login etc. werden weiterhin über Formen `` realsiert. Dafür stellt die neue Version [Aktionen](/frontend/referenz/aktionen) zur Verfügung. * Statt Form-Tags, die der `` im Element `action=""` mitgegen wurden, wird jetzt das gewünschte Template mittels `{{= $wsViews.current.url() }}` oder `{{= $wsViews.viewUrl('login.htm')}}` mitgegeben, z.B. * `` * jetzt * `` * oder * `` ## HTML-Comment * Anstelle von `WS-TplComment` wird jetzt verwendet: `{{ # Dein Kommentar # }}` ## Inventory * Bestandsinformationen werden über das Modul [\$wsInventory](/frontend/referenz/module/wsinventory) geladen * Bevor Bestandsinformationen angezeigt werden, müssen sie geladen werden mit, z.B. mit\ `{{ var $myVariableForInventoryInfo = $wsInventory.load($product.id) }}` * `PR-Inventory` wird jetzt aufgebaut mit `{{ if $myVariableForInventoryInfo.active }}` * `PR-InventoryState()` wird jetzt abgebildet über: * `{{= $myVariableForInventoryInfo.state }}` und * `{{ switch $myVariableForInventoryInfo.state }}` mit den jeweiligen `{{ case "xxx"}}`-Blöcken ## Links * Sämtliche Seiten-Verlinkungen werden über das Modul [\$wsViews](/frontend/referenz/module/wsviews) realisiert, z.B. * `URL-Homepage` -> `{{= $wsViews.host }}` * `WS-LoadTpl(your-template.htm)` ->`{{= $wsViews.viewUrl('your-template.htm')}}` * `WS-SSLLoadTpl()` → `{{= $wsViews.viewUrl('your-template.htm')}}` * Das schließt auch Verlinkungen wie zur Warenkorbseite, Merkliste, Login etc. sein, für die es in der V8s eigene Link-Tags gab, z.B. * `WS-BasketLink` → `{{= $wsViews.viewUrl('basket.htm')}}` * `WS-MemoListLink` → `{{= $wsViews.viewUrl('memolist.htm')}}` * `WS-LoginLink` → `{{= $wsViews.viewUrl('login.htm')}}` * `WS-LogoutLink` → `{{= $wsViews.viewUrl('logout.htm')}}` * `WS-UserAccountLink` -> `{{= $wsViews.viewUrl('account.htm')}}` ## Login * Kundenkonto-Informationen werden über das Modul [\$wsAccount](/frontend/referenz/module/wsAccount) geladen * `WS-LoginLink` wird jetzt umgesetzt mit `{{= $wsViews.viewUrl('your-file.htm')}}` * `ST-LoggedIn` wird jetzt geprüft mit `{{ if $wsAccount.isLoggedIn }}` ## Logout * Kundenkonto-Informationen werden über das Modul [\$wsAccount](/frontend/referenz/module/wsAccount) geladen * `WS-LogoutLink` wird jetzt umgesetzt mit `{{= $wsActions.url('Logout', $wsViews.viewUrl('logout.htm'), {})}}` ## Memolist * Die Merkliste wird über das Modul [\$wsWatchList](/frontend/referenz/module/wswatchlist) geladen * `ST-MemoList_OK` wird jetzt geprüft mit `{{ if $wsWatchList.items }} ... {{ /if }}` * `WS-MemoListEntries` wird jetzt dargestellt mit `{{= $wsWatchList.items | len }}` ## Meta-Tags * `` wird nicht mehr benötigt * Die Funktion `{{=static('')}}` enthält die Basis-Verzeichnisinformation. * `WS-RobotCanonical` wird jetzt aufgebaut mit `{{= $wsViews.host }}` und `{{= $wsViews.current.url() }}` ## Payments * Übersicht aller konfigurierten Zahlarten * statt `TAC-P-Data` jetzt `{{ foreach $myVariableForAllPayments in $wsConfig.payments }}` * Zahlungsarten innerhalb des Bestellablaufes werden zudem über das Modul [\$wsCheckout](/frontend/referenz/module/wscheckout) geladen, z.B. gewählte Zahlungsart ## Products * Produkt-Informationen werden über das Modul [\$wsProducts](/frontend/referenz/module/wsproducts) geladen ## Search * Umsetzung aller Such- und Filterfunktionen erfolgt über das Suchmodul [WEBSALE Search](https://websale.atlassian.net/wiki/spaces/Doku/pages/2913992717/WEBSALE+search) ## ShippingMethod * Statt “deliverer” und “delivery” verwenden wir jetzt “shipping” und “shippingMethods” * Übersicht aller konfigurierten Lieferarten * statt `TAC-D-Data` jetzt `{{ foreach $yVariableForAllShippings in $wsConfig.shippingMethods }}` * Versandinformationen innerhalb des Bestellablaufes werden zudem über das Modul [\$wsCheckout](/frontend/referenz/module/wscheckout) geladen, z.B. gewählte Versandart ## Useraccount * Kundenkonto-Informationen werden über das Modul [\$wsAccount](/frontend/referenz/module/wsAccount) geladen * `WS-UserAccountLink` -> `{{= $wsViews.viewUrl('account.htm')}}` # WEBSALE V8s Dokumentation Source: https://dokumentation.websale.de/v8s Einstieg in die Dokumentation der WEBSALE V8s-Generation: Grundlagen, Wegweiser, Referenz und Materialien. **Diese Dokumentation befindet sich aktuell im Aufbau.** Während dem Aufbau empfehlen wir Ihnen die [bisherige V8s-Dokumentation](https://doku.websale.net/). Aufbau und Konzepte von WEBSALE V8s verstehen. Schritt für Schritt durch die typischen Aufgaben im Shop. Nachschlagewerk für Konfiguration, Parameter und Template-Code. Vorlagen, Beispiele und Dateien zum Herunterladen. # Filtern & Sortieren auf Kategorien Source: https://dokumentation.websale.de/ws-search/integration-in-die-templates-storefront/filtern-sortieren-auf-kategorien WEBSALE | search auf Kategorieseiten einbinden: Filtern und Sortieren nach Farbe, Preis oder Verfügbarkeit per WebComponents und JavaScript-Skripten. Das Modul **WEBSALE | search** ermöglicht nicht nur die klassische Produktsuche, sondern kann auch zur Filterung und Sortierung auf Kategorieseiten genutzt werden. Dadurch können Kunden die angezeigten Produkte gezielt nach Kriterien wie Farbe, Preis oder Verfügbarkeit eingrenzen und in einer gewünschten Reihenfolge anzeigen lassen. Diese Dokumentation beschreibt, wie die **Filter- und Sortierfunktion für Kategorien** in den Shop integriert wird. Dabei wird zwischen zwei Szenarien unterschieden: * Falls die **Suche & Suchergebnisseite bereits in den Shop integriert** wurde, sind viele erforderliche Komponenten bereits vorhanden, und es sind nur gezielte Anpassungen für die Kategorie-Templates erforderlich. * Falls **keine WEBSALE Suche genutzt wird** (z. B. weil ein externer Dienstleister wie Findologic oder FACT Finder für die Suche zuständig ist), müssen die notwendigen Komponenten und Skripte vollständig für die Kategorieseiten eingebunden werden. In den folgenden Abschnitten wird erläutert, welche Anpassungen für die verschiedenen Szenarien erforderlich sind und welche WebComponents und Skripte für eine reibungslose Integration genutzt werden müssen. *** ## Szenario: Suche & Suchergebnisseite bereits integriert ### Bereits vorhandene Komponenten Falls die Suche bereits im Shop implementiert wurde, dann sind die folgenden Komponenten bereits in allen Templates eingebunden und müssen nicht erneut integriert werden: * WEBSALE JavaScript Bibliothek * JavaScript Bundle (`ws-search-component-.js`) * Kommunikationskomponente (`ws-search`) * Sucheingabefeld mit optionaler Suggestfunktion (`ws-search-box`) * Such-Event-Dispatcher & Weiterleitung von Suchanfragen (`wsResultDispatcher.subscribe`) ### Anpassungen für die Kategorie-Seite (`ws_category.htm`) Für das Kategorietemplate `ws_category.htm` müssen dann nur die folgenden zusätzlichen Anpassungen vorgenommen werden: * Einbindung der Komponente `ws-search-result` * Template-Platzhalter für die Produktbox (`