Introduction
Hello there. Great that you are interested in creating an app that interacts with the Beyond API. Your contribution will help to give merchants everything they need to easily sell goods online using the ePages Store product. So come and join the ePages Beyond network.
Creating an app is complex and has many aspects that need to be considered. In the following sections we will guide you through all relevant topics regarding the development of an app for our e-commerce solution.
If you are new to app development but still eager to take the challenge, take a look at our JavaScript and Rails tutorials for more detailed information.
Put your idea into action!
Note
|
If you plan to submit the app you’re working on, please be sure to read and understand our submission guidelines. |
App integration levels
You want to create an app using the Beyond API? Great! ePages offers three different integration levels for your app. Which level is most suitable will be evaluated and decided after you have submitted your app.
Standard app integration
If your app is integrated as standard, it will appear in the app store alongside other available apps. There, merchants can install and uninstall your app as they wish. The app overview can be accessed from the main navigation of the cockpit.

System app integration
An app on system level is deeply integrated into the product. It is pre-installed and does not appear in the app store. Merchants can thus not uninstall it. The app will act like a natively implemented core feature of the product.

Bundle app integration
The bundle app integration option combines aspects from an integration on standard and on system level. The app is pre-installed, but unlike the system app, it will appear in the app overview of the merchant’s cockpit. There, merchants can uninstall the app and re-install it as they wish. The app store can be accessed from the sidebar of the cockpit. The bundle integration option may be useful when an app should already be available during the set-up of the shop but is more of an optional service than a core feature of the product.
If you have further questions or need more information about the integration levels, please contact us: apps@epages.com
App conception
Before you can start coding your app, you first need to put some thoughts into its concept, basic features and requirements.
Note
|
If you plan to submit the app you’re working on, please be sure to read and understand our submission guidelines. |
Scopes
In order to create an app for a Beyond online shop you need access to our merchants' data. By setting OAuth scopes you specify exactly which permissions your app requires.
Here’s the list of the scopes we provide and what they’re used for.
Scope | Used for |
---|---|
|
Create product category |
|
List product categories, Show product category details, Search product categories, Find manual categories, Find used category tags, Find category manufacturers |
|
Update all product category properties, Update product category partially (json), Add multiple products to product categories, Remove multiple products from product categories |
|
Delete product category |
|
Create coupon campaign, Update coupon codes |
|
List coupon campaigns, Show coupon campaign details, List coupon codes |
|
Update coupon campaign, Update coupon campaign status |
|
Delete coupon campaign |
|
Create cancelation process, Cancel order |
|
List cancelation processes, Show cancelation process details |
|
Show customer details in customer account, Show shipping address in customer account, Show billing address in customer account, List orders in customer account, Show order details in customer account |
|
Update shipping address in customer account, Update billing address in customer account |
|
Delete customer account |
|
List checkout settings |
|
Update checkout settings |
|
Create customer |
|
List customers, Show customer details, List customer events |
|
Update customer |
|
Delete customer |
|
Show language details, List languages, List supported languages |
|
Update legal content |
|
Show legal details |
|
Update legal resource partially (json) |
|
Create location |
|
List locations, Show location details |
|
Update location |
|
Delete location |
|
Create newsletter target, Update newsletter target, Delete newsletter target |
|
List order events |
|
Create order |
|
List orders, List unviewed orders, Show order details, Find used shipping countries, Create webhook subscription, Update webhook subscription, List order filter categories, List order documents, Show order document details, Create order export, Show order export status, Show order batch action status, Combine multiple invoices, Combine multiple pickup packing slips, Combine multiple shipping packing slips |
|
Update order note, Update billing address, Update shipping address, Create invoice, Send order document, Mark order as viewed, Mark multiple orders as viewed, Mark multiple orders as unviewed, Create multiple invoices, Create multiple pickup processes, Create multiple shipping processes |
|
List order processes |
|
List order settings |
|
Update order settings |
|
Retrieve payment method definition, Retrieve payment methods, List payment method definitions, Create payment method definition, Update payment method definition, Delete payment method definition, Create payment method, Delete payment method, Retrieve shop ID, Approve payment, Cancel payment, Fail payment, Set payment status |
|
Create category customer group discount |
|
List category customer group discounts by category, List category customer group discounts by customer group, Show category customer group discount details |
|
Update category customer group discount |
|
Delete category customer group discount |
|
Create product customer group discount |
|
List product customer group discounts by product, List product customer group discounts by customer group, Show product customer group discount details |
|
Update product customer group discount |
|
Delete product customer group discount |
|
Create product attribute definition |
|
List product attribute definitions, Show product attribute definition details |
|
Delete product attribute definition |
|
Create product attribute |
|
Delete product attribute |
|
Show product attribute details, List product attributes |
|
Update product attribute |
|
Create product cross-sell |
|
List product cross-sells, Show product cross-sell details |
|
Update product cross-sell |
|
Delete product cross-sell |
|
Show product availability details, Show variation availability details |
|
Enable purchasability for variation, Disable purchasability for variation, Adjust stock level of variation, Enable stock management, Disable stock management, Adjust stock level, Update reserve stock, Enable purchasability, Disable purchasability |
|
Create product, Create variation product |
|
List products including variation products, Show product details, Show variation product details, Find product by SKU, Find used tags, Find manufacturers, Search and filter products, List product filter categories, Show product filter category details, Show variation details, List variations, List variation properties, List product attachments, Show product attachment details, List product images, Show product image details, Create webhook subscription, Update webhook subscription, List product videos, Show product video details, List variation images, List variation images of all variations, Show variation image details, List variation attributes, Show variation attribute details, List additional product descriptions |
|
Update product partially, Update multiple products partially, Update variation product partially, Update variation partially (json), Update variation properties, Add product attachment, Delete product attachment, Add product image, Add multiple product images, Upload product image, Upload multiple product images, Upload external product image, Delete product image, Assign product image as default image, Sort product images, Add variation image, Add multiple variation images, Add multiple variation images to multiple variations, Upload variation image, Upload multiple variation images, Upload multiple variation images for multiple variations, Sort variation images, Sort variation images of multiple variations, Delete variation image, Delete variation images of multiple variations, Assign variation image as default image, Add product video, Update product video, Delete product video, Update variation attribute, Sort variation attributes, Assign variation attribute as variation images differentiator, Create variation attribute value, Sort variation attribute values, Delete variation attribute values of multiple variation attributes, Add tags to multiple products, Remove tags from multiple products, Add additional product description, Update additional product description, Sort additional product descriptions, Delete additional product description |
|
Delete product, Delete multiple products |
|
List payment methods, Show payment method details, Generate referral URI, Show merchant account details |
|
Update payment method, Sort payment methods, Activate payment method, Deactivate payment method |
|
List payment processes, Show payment process details, Show active payment process details, Show online payment process details |
|
Mark payment process as voided, Mark payment process as paid, Capture payment |
|
List refund processes, Show refund process details, Show active refund process details |
|
Mark refund process as paid |
|
Create return process |
|
List return processes, Show return process details |
|
Create script tag, Update script tag, Delete script tag |
|
Update address partially (json) |
|
Create shop attribute |
|
List shop attributes, Show shop attribute details |
|
Update shop attribute |
|
Delete shop attribute |
|
Create shop image, Upload shop image |
|
List shop images, Show shop image details, Find shop images by label |
|
Delete shop image |
|
Update shop partially (json) |
|
Create shipping process, Create pickup process |
|
List shipping processes, Show shipping process details, List pickup processes, Show pickup process details |
|
Mark shipment as shipped, Mark shipment as delivered, Mark pickup process as picked up |
|
Create shipping zone, Create pickup option |
|
Show shipping zone details, List shipping zones, Show details of shipping method in shipping zone, Show details of shipping method with weight-based price in shipping zone, List shipping methods of shipping zone, List pickup options, Show pickup option details |
|
Update shipping zone, Sort shipping zones, Create shipping method in shipping zone, Create shipping method with weight-based price in shipping zone, Update shipping method in shipping zone, Sort shipping methods in shipping zone, Delete shipping method in shipping zone, Update pickup option, Sort pickup options |
|
Delete shipping zone, Delete pickup option |
Events
Events can be triggered when a customer executes a specific action in an ePages online shop. This can, for example, be a customer accessing a shop’s page, or adding a product to the cart. If you have implemented an event in your application, you will be informed about related actions and can react accordingly. Furthermore, your app will receive information related to the event, such as the current page a user is on.
Note
|
Please be sure to regularly check our change log to keep track of updates and changes on properties that might affect your app. |
Available events
In the following table, you can find all available events and the circumstances that trigger those events. For more detailed information on a specific event, see the section Examples.
Event | Description |
---|---|
|
Is triggered when the customer opens or reloads a page. Informs about the path of the page. |
|
Is triggered when the customer accesses a product detail page. Informs about the respective product as well as the current state of the cart. |
|
Is triggered when the customer selects a link to a product detail page, for example, in a product category or on the search results page. Please note that the event is not triggered when the customer selects a link to a product detail page in a product slider. Informs about the respective product as well as the source of the link. |
|
Is triggered when the customer selects a page displaying a product category. Informs about the respective category and included products. |
|
Is triggered when the customer accesses the search results page. The event is also triggered when the customer updates the search results page, for example, by selecting the Show more button. Informs about the number of search results, the search query, and the products included in the search results. |
|
Is triggered when the customer accesses the cart. Informs about the current state of the cart, for example, about included items. |
|
Is triggered when the customer adds a product to the cart. Provides information about the current state of the cart and the added product. |
|
Is triggered when the quantity of a product in the cart is changed. This also includes the removal of a product. Informs about the quantity change and the affected line item. |
|
Is triggered when the cart is changed on the cart overview. Informs about the current state of the cart, for example, about included items. |
|
Is triggered when a customer successfully signs up for a customer account. Informs about the customer’s email address and name. |
|
Is triggered when a customer successfully signs in to their customer account. Informs about the customer’s email address. |
|
Is triggered when a customer selects a shipping method or pickup option during checkout. Informs about the selected shipping method or pickup option. |
|
Is triggered when a customer selects a payment method during checkout. Informs about the selected payment method. |
|
Is triggered when a customer submits an order. Provides information about the ordered cart, such as the grand total, the selected payment method, and the selected shipping method. After submitting the order, the customer might need to take further actions before the order is completed, for example, on payment provider pages. |
|
Is triggered when a customer who accepted all cookies reaches the order confirmation page after completing a purchase. Does not provide further information. |
Examples
This section explains how to make use of the single events and what to expect from them.
page:view
To get more information about this event, you can use the following snippet:
if (window.eComEventTarget) { window.eComEventTarget.addEventListener('page:view', function (event) { console.log('page:view', { url: event.detail.url, }) }) }
Here’s an example of what you can get:
url: /i/about-us
product:view
To get more information about this event, you can use the following snippet:
if (window.eComEventTarget) { window.eComEventTarget.addEventListener('product:view', function (event) { console.log('product:view', { product: event.detail.product, cart: event.detail.cart, }) }) }
Here’s an example of what you can get:
product: { availabilityText: "components.productComponent.availability.IN_STOCK" available: true basePrice: {refQuantity: {…}, refPrice: {…}, formatted: "1 m³ = €0.12", quantity: {…}} bulkPrices: null conditionMicrodata: "ConditionNew" customAttributes: null deliveryPeriod: "2-3" deliveryPeriodUnit: "DAYS" description: null energyLabel: null energyLabelSourceFile: null gtin: null hasCrossSelling: false hasStockLevel: true hasVariations: false href: "/p/homemade-cherry-jam" image: null isVariationMaster: false isVariationProduct: false isVisible: true links: (5) [{…}, {…}, {…}, {…}, {…}] listPrice: null // deprecated, use strikePrice and isStrikePriceRRP instead lowestPrice: null mainCategoryId: null manufacturer: null manufacturerPrice: null // deprecated, use strikePrice and isStrikePriceRRP instead metaDescription: "" name: "Homemade Cherry Jam" onStock: true outOfStock: false pickupPeriod: "" price: {amount: 40, currency: "EUR", taxType: "NET", formatted: "€40.00"} productDataSheet: null productId: "5954B706-E701-F357-A52D-D5809AB3F606" productVariationSelection: null productVariationValues: null sku: "1007" slideshow: [{…}, {…}, {…}, {…}] slug: "homemade-cherry-jam" stockLevelClass: "in" stockLevelMicrodata: "InStock" strikePrice: null isStrikePriceRRP: false title: "Homemade Cherry Jam" variationMaster: null variations: null vatNote: "components.productComponent.priceExclusiveVat" warnStock: false weight: null } cart: { billingAddress: null canHaveCoupon: true cartId: "5C06901F-150A-3D9B-B144-D509AB34800" checkoutButtons: [] checkoutState: null checkoutUrl: "/checkout/personal-data" coupon: null couponCampaign: null customerEmail: null grandAmount: "€76.01" grandAmountNote: "components.productComponent.priceExclusiveVat" grandTotal: {amount: 76.01, currency: "EUR", formatted: "€76.01"} minimumOrderValue: null mustAcceptTermsAndConditions: false netAmount: "€76.01" paymentLineItem: {lineItemPrice: {…}, paymentMethod: {…}} pickupToken: "ZjM3M2Q2YmY4jkFjYWRlZTIzZTBlYzQwMDU4MjYzZjYwNDNhZGY0NWM1N2JiNjZhMGI0YWNlNWFkYzU4ZTQ3OF8xNTQzOTM5MjIx" potentialBasketDiscounts: null productLineItems: [{…}, {…}, {…}] registerSessionUrl: "" shippingAddress: null shippingLineItem: {lineItemPrice: {…}, shippingMethod: {…}} status: null subAmount: "€76.01" subAmountValue: 76.01 taxType: "NET" taxes: [] totalBasketDiscount: null totalNumberOfItems: 3 _links: null }
product:click
To get more information about this event, you can use the following snippet:
if (window.eComEventTarget) { window.eComEventTarget.addEventListener('product:click', function (event) { console.log('product:click', { type: event.detail.type, detail: event.detail.detail, product: event.detail.product, productIndex: event.detail.productIndex, }) }) }
Here’s an example of what you can get:
detail: "Cherry Jam" product: { availabilityText: "components.productComponent.availability.IN_STOCK" available: true basePrice: {refQuantity: {…}, refPrice: {…}, formatted: "1 m³ = €0.12", quantity: {…}} bulkPrices: null conditionMicrodata: "ConditionNew" customAttributes: null deliveryPeriod: "2-3" deliveryPeriodUnit: "DAYS" description: null energyLabel: null energyLabelSourceFile: null gtin: null hasCrossSelling: false hasStockLevel: true hasVariations: false href: "/p/homemade-cherry-jam" image: null isVariationMaster: false isVariationProduct: false isVisible: true links: (5) [{…}, {…}, {…}, {…}, {…}] listPrice: null // deprecated, use strikePrice and isStrikePriceRRP instead lowestPrice: null mainCategoryId: null manufacturer: null manufacturerPrice: null // deprecated, use strikePrice and isStrikePriceRRP instead metaDescription: "" name: "Homemade Cherry Jam" onStock: true outOfStock: false pickupPeriod: "" price: {amount: 40, currency: "EUR", taxType: "NET", formatted: "€40.00"} productDataSheet: null productId: "5954B706-E701-F357-A52D-D5809AB3F606" productVariationSelection: null productVariationValues: null sku: "1007" slideshow: [{…}, {…}, {…}, {…}] slug: "homemade-cherry-jam" stockLevelClass: "in" stockLevelMicrodata: "InStock" strikePrice: null isStrikePriceRRP: false title: "Homemade Cherry Jam" variationMaster: null variations: null vatNote: "components.productComponent.priceExclusiveVat" warnStock: false weight: null } productIndex: 1 type: "search"
category:view
To get more information about this event, you can use the following snippet:
if (window.eComEventTarget) { window.eComEventTarget.addEventListener('category:view', function (event) { console.log('category:view', { category: event.detail.category, products: event.detail.products, }) }) }
Here’s an example of what you can get:
category: { categoryId: "5AD608E0-22C3-0009-F213-D5823AB36AC8" imageSize: "L" pageSize: 12 } products: Array(2) { 0: { availabilityText: "components.productComponent.availability.IN_STOCK" available: true basePrice: {refQuantity: {…}, refPrice: {…}, formatted: "1 m³ = €0.12", quantity: {…}} bulkPrices: null conditionMicrodata: "ConditionNew" customAttributes: null deliveryPeriod: "2-3" deliveryPeriodUnit: "DAYS" description: null energyLabel: null energyLabelSourceFile: null gtin: null hasCrossSelling: false hasStockLevel: true hasVariations: false href: "/p/homemade-cherry-jam" image: null isStrikePriceRRP: null isVariationMaster: false isVariationProduct: false isVisible: true links: (5) [{…}, {…}, {…}, {…}, {…}] listPrice: null // deprecated, use strikePrice and isStrikePriceRRP instead lowestPrice: null mainCategoryId: null manufacturer: null manufacturerPrice: null // deprecated, use strikePrice and isStrikePriceRRP instead metaDescription: "" name: "Homemade Cherry Jam" onStock: true outOfStock: false pickupPeriod: "" price: {amount: 40, currency: "EUR", taxType: "NET", formatted: "€40.00"} productDataSheet: null productId: "5954B706-E701-F357-A52D-D5809AB3F606" productVariationSelection: null productVariationValues: null sku: "1007" slideshow: [{…}, {…}, {…}, {…}] slug: "homemade-cherry-jam" stockLevelClass: "in" stockLevelMicrodata: "InStock" strikePrice: null title: "Homemade Cherry Jam" variationMaster: null variations: null vatNote: "components.productComponent.priceExclusiveVat" warnStock: false weight: null } 1: { availabilityText: "components.productComponent.availability.IN_STOCK" available: true basePrice: {refQuantity: {…}, refPrice: {…}, formatted: "1 m³ = €0.12", quantity: {…}} bulkPrices: null conditionMicrodata: "ConditionNew" customAttributes: null deliveryPeriod: "1-2" deliveryPeriodUnit: "DAYS" description: null energyLabel: null energyLabelSourceFile: null gtin: null hasCrossSelling: false hasStockLevel: true hasVariations: false href: "/p/homemade-strawberry-jam" image: null isStrikePriceRRP: null isVariationMaster: false isVariationProduct: false isVisible: true links: (5) [{…}, {…}, {…}, {…}, {…}] listPrice: null // deprecated, use strikePrice and isStrikePriceRRP instead lowestPrice: null mainCategoryId: null manufacturer: null manufacturerPrice: null // deprecated, use strikePrice and isStrikePriceRRP instead metaDescription: "" name: "Homemade Strawberry Jam" onStock: true outOfStock: false pickupPeriod: "" price: {amount: 36, currency: "EUR", taxType: "NET", formatted: "€36.00"} productDataSheet: null productId: "5954B8805-E701-F357-A52D-D5809AB3F606" productVariationSelection: null productVariationValues: null sku: "1008" slideshow: [{…}, {…}, {…}, {…}] slug: "homemade-strawberry-jam" stockLevelClass: "in" stockLevelMicrodata: "InStock" strikePrice: null title: "Homemade Strawberry Jam" variationMaster: null variations: null vatNote: "components.productComponent.priceExclusiveVat" warnStock: false weight: null } }
searchResults:view
To get more information about this event, you can use the following snippet:
if (window.eComEventTarget) { window.eComEventTarget.addEventListener('searchResults:view', function (event) { console.log('searchResults:view', { products: event.detail.products, query: event.detail.query, }) }) }
Here’s an example of what you can get:
products: Array(2) { 0: { availabilityText: "components.productComponent.availability.IN_STOCK" available: true basePrice: {refQuantity: {…}, refPrice: {…}, formatted: "1 m³ = €0.12", quantity: {…}} bulkPrices: null conditionMicrodata: "ConditionNew" customAttributes: null deliveryPeriod: "2-3" deliveryPeriodUnit: "DAYS" description: null energyLabel: null energyLabelSourceFile: null gtin: null hasCrossSelling: false hasStockLevel: true hasVariations: false href: "/p/homemade-cherry-jam" image: null isStrikePrice: false isVariationMaster: false isVariationProduct: false isVisible: true links: (5) [{…}, {…}, {…}, {…}, {…}] listPrice: null // deprecated, use strikePrice and isStrikePriceRRP instead lowestPrice: null mainCategoryId: null manufacturer: null manufacturerPrice: null // deprecated, use strikePrice and isStrikePriceRRP instead metaDescription: "" name: "Homemade Cherry Jam" onStock: true outOfStock: false pickupPeriod: "" price: {amount: 40, currency: "EUR", taxType: "NET", formatted: "€40.00"} productDataSheet: null productId: "5954B706-E701-F357-A52D-D5809AB3F606" productVariationSelection: null productVariationValues: null sku: "1007" slideshow: [{…}, {…}, {…}, {…}] slug: "homemade-cherry-jam" stockLevelClass: "in" stockLevelMicrodata: "InStock" strikePrice: null title: "Homemade Cherry Jam" variationMaster: null variations: null vatNote: "components.productComponent.priceExclusiveVat" warnStock: false weight: null } 1: { availabilityText: "components.productComponent.availability.IN_STOCK" available: true basePrice: {refQuantity: {…}, refPrice: {…}, formatted: "1 m³ = €0.12", quantity: {…}} bulkPrices: null conditionMicrodata: "ConditionNew" customAttributes: null deliveryPeriod: "1-2" deliveryPeriodUnit: "DAYS" description: null energyLabel: null energyLabelSourceFile: null gtin: null hasCrossSelling: false hasStockLevel: true hasVariations: false href: "/p/homemade-strawberry-jam" image: null isStrikePriceRRP: false isVariationMaster: false isVariationProduct: false isVisible: true links: (5) [{…}, {…}, {…}, {…}, {…}] listPrice: null // deprecated, use strikePrice and isStrikePriceRRP instead lowestPrice: null mainCategoryId: null manufacturer: null manufacturerPrice: null // deprecated, use strikePrice and isStrikePriceRRP instead metaDescription: "" name: "Homemade Strawberry Jam" onStock: true outOfStock: false pickupPeriod: "" price: {amount: 36, currency: "EUR", taxType: "NET", formatted: "€36.00"} productDataSheet: null productId: "5954B8805-E701-F357-A52D-D5809AB3F606" productVariationSelection: null productVariationValues: null sku: "1008" slideshow: [{…}, {…}, {…}, {…}] slug: "homemade-strawberry-jam" stockLevelClass: "in" stockLevelMicrodata: "InStock" strikePrice: null title: "Homemade Strawberry Jam" variationMaster: null variations: null vatNote: "components.productComponent.priceExclusiveVat" warnStock: false weight: null } length: 2 } query: { q: "Jam" }
cart:view
To get more information about this event, you can use the following snippet:
if (window.eComEventTarget) { window.eComEventTarget.addEventListener('cart:view', function (event) { console.log('cart:view', { cart: event.detail.cart, }) }) }
Here’s an example of what you can get:
cart: { billingAddress: null canHaveCoupon: true cartId: "5C06901F-150A-3D9B-B144-D509AB34800" checkoutButtons: [] checkoutState: null checkoutUrl: "/checkout/personal-data" coupon: null couponCampaign: null customerEmail: null grandAmount: "€76.01" grandAmountNote: "components.productComponent.priceExclusiveVat" grandTotal: {amount: 76.01, currency: "EUR", formatted: "€76.01"} minimumOrderValue: null mustAcceptTermsAndConditions: false netAmount: "€76.01" paymentLineItem: {lineItemPrice: {…}, paymentMethod: {…}} pickupToken: "ZjM3M2Q2YmY4jkFjYWRlZTIzZTBlYzQwMDU4MjYzZjYwNDNhZGY0NWM1N2JiNjZhMGI0YWNlNWFkYzU4ZTQ3OF8xNTQzOTM5MjIx" potentialBasketDiscounts: null productLineItems: [{…}, {…}, {…}] registerSessionUrl: "" shippingAddress: null shippingLineItem: {lineItemPrice: {…}, shippingMethod: {…}} status: null subAmount: "€76.01" subAmountValue: 76.01 taxType: "NET" taxes: [] totalBasketDiscount: null totalNumberOfItems: 3 _links: null }
cart:add
To get more information about this event, you can use the following snippet:
if (window.eComEventTarget) { window.eComEventTarget.addEventListener('cart:add', function (event) { console.log('cart:add', { cart: event.detail.cart, product: event.detail.product, quantity: event.detail.quantity, }) }) }
Here’s an example of what you can get:
cart: { billingAddress: null canHaveCoupon: true cartId: "5C06901F-150A-3D9B-B144-D509AB34800" checkoutButtons: [] checkoutState: null checkoutUrl: "/checkout/personal-data" coupon: null couponCampaign: null customerEmail: null grandAmount: "€76.01" grandAmountNote: "components.productComponent.priceExclusiveVat" grandTotal: {amount: 76.01, currency: "EUR", formatted: "€76.01"} minimumOrderValue: null mustAcceptTermsAndConditions: false netAmount: "€76.01" paymentLineItem: {lineItemPrice: {…}, paymentMethod: {…}} pickupToken: "ZjM3M2Q2YmY4jkFjYWRlZTIzZTBlYzQwMDU4MjYzZjYwNDNhZGY0NWM1N2JiNjZhMGI0YWNlNWFkYzU4ZTQ3OF8xNTQzOTM5MjIx" potentialBasketDiscounts: null productLineItems: [{…}, {…}, {…}] registerSessionUrl: "" shippingAddress: null shippingLineItem: {lineItemPrice: {…}, shippingMethod: {…}} status: null subAmount: "€76.01" subAmountValue: 76.01 taxType: "NET" taxes: [] totalBasketDiscount: null totalNumberOfItems: 3 _links: null } product: { availabilityText: "components.productComponent.availability.IN_STOCK" available: true basePrice: {refQuantity: {…}, refPrice: {…}, formatted: "1 m³ = €0.12", quantity: {…}} bulkPrices: null conditionMicrodata: "ConditionNew" customAttributes: null deliveryPeriod: "2-3" deliveryPeriodUnit: "DAYS" description: null energyLabel: null energyLabelSourceFile: null gtin: null hasCrossSelling: false hasStockLevel: true hasVariations: false href: "/p/homemade-cherry-jam" image: null isStrikePriceRRP: false isVariationMaster: false isVariationProduct: false isVisible: true links: (5) [{…}, {…}, {…}, {…}, {…}] listPrice: null // deprecated, use strikePrice and isStrikePriceRRP instead lowestPrice: null mainCategoryId: null manufacturer: null manufacturerPrice: null // deprecated, use strikePrice and isStrikePriceRRP instead metaDescription: "" name: "Homemade Cherry Jam" onStock: true outOfStock: false pickupPeriod: "" price: {amount: 40, currency: "EUR", taxType: "NET", formatted: "€40.00"} productDataSheet: null productId: "5954B706-E701-F357-A52D-D5809AB3F606" productVariationSelection: null productVariationValues: null sku: "1007" slideshow: [{…}, {…}, {…}, {…}] slug: "homemade-cherry-jam" stockLevelClass: "in" stockLevelMicrodata: "InStock" strikePrice: null title: "Homemade Cherry Jam" variationMaster: null variations: null vatNote: "components.productComponent.priceExclusiveVat" warnStock: false weight: null } quantity: 1
cart:setQuantity
To get more information about this event, you can use the following snippet:
if (window.eComEventTarget) { window.eComEventTarget.addEventListener('cart:setQuantity',function(event) { console.log('cart:setQuantity', { lineItem: event.detail.lineItem, quantity: event.detail.quantity, quantityDelta: event.detail.quantityDelta, }) }) }
Here’s an example of what you can get:
lineItem: { energyLabel: null energyLabelSourceFile: null essentialFeatures: [] imageUrl: "https://pm.epages.com/epages/apidocu.sf/api/core-storage/images/jam-928256_1920.jpg" lineItemCouponDiscount: null lineItemId: "29771d97-8ba1-45e0-986e-4f15842fb407" lineItemPrice: {amount: 8.8, currency: "EUR", taxType: "GROSS", formatted: "€8.80"} name: "Homemade Cherry Jam" productId: "66f82e8b-e211-4d5e-8a15-6bfb7a0906a3" productUrl: "/p/homemade-cherry-jam" quantity: 1 singleItemPrice: {amount: 8.8, currency: "EUR", taxType: "GROSS", formatted: "€8.80"} sku: "1000" slug: "homemade-cherry-jam" taxClass: "REGULAR" variationString: "" } quantity: 2 quantityDelta: 1
cart:update
To get more information about this event, you can use the following snippet:
if (window.eComEventTarget) { window.eComEventTarget.addEventListener('cart:update',function(event) { console.log('cart:update', { cart: event.detail.cart, }) }) }
Here’s an example of what you can get:
cart: { billingAddress: null canHaveCoupon: true cartId: "5C06901F-150A-3D9B-B144-D509AB34800" checkoutButtons: [] checkoutState: null checkoutUrl: "/checkout/personal-data" coupon: null couponCampaign: null customerEmail: null grandAmount: "€76.01" grandAmountNote: "components.productComponent.priceExclusiveVat" grandTotal: {amount: 76.01, currency: "EUR", formatted: "€76.01"} minimumOrderValue: null mustAcceptTermsAndConditions: false netAmount: "€76.01" paymentLineItem: {lineItemPrice: {…}, paymentMethod: {…}} pickupToken: "ZjM3M2Q2YmY4jkFjYWRlZTIzZTBlYzQwMDU4MjYzZjYwNDNhZGY0NWM1N2JiNjZhMGI0YWNlNWFkYzU4ZTQ3OF8xNTQzOTM5MjIx" potentialBasketDiscounts: null productLineItems: [{…}, {…}, {…}] registerSessionUrl: "" shippingAddress: null shippingLineItem: {lineItemPrice: {…}, shippingMethod: {…}} status: null subAmount: "€76.01" subAmountValue: 76.01 taxType: "NET" taxes: [] totalBasketDiscount: null totalNumberOfItems: 3 _links: null }
customer:signUp
To get more information about this event, you can use the following snippet:
if (window.eComEventTarget) { window.eComEventTarget.addEventListener('customer:signUp',function(event) { console.log('customer:signUp', { email: event.detail.customer.email, firstName: event.detail.customer.firstName, lastName: event.detail.customer.lastName, }) }) }
Here’s an example of what you can get:
customer: { email: "a.alsterh@example.com" firstName: "Astrid" lastName: "Alster"}
customer:signIn
To get more information about this event, you can use the following snippet:
if (window.eComEventTarget) { window.eComEventTarget.addEventListener('customer:signIn',function(event) { console.log('customer:signIn', { email: event.detail.customer.email, }) }) }
Here’s an example of what you can get:
customer: { email: "a.alsterh@example.com"}
shippingMethod:select
To get more information about this event, you can use the following snippet:
if (window.eComEventTarget) { window.eComEventTarget.addEventListener('shippingMethod:select',function(event) { console.log('shippingMethod:select', { shippingMethod: event.detail.shippingMethod, }) }) }
Here’s an example of what you can get:
shippingMethod: { description: "Express Delivery" freeShippingValue: null lineItemPrice: {amount: 4.95, currency: 'EUR', taxType: 'GROSS', formatted: '€4.95'} name: "Express" position: 0 selectable: true weightBasedPrice: null _id: "3d0d8950-ce60-44ta-b375-cb2f21acab5c" _links: {self: {…}}
paymentMethod:select
To get more information about this event, you can use the following snippet:
if (window.eComEventTarget) { window.eComEventTarget.addEventListener('paymentMethod:select',function(event) { console.log('paymentMethod:select', { paymentMethod: event.detail.paymentMethod, }) }) }
Here’s an example of what you can get:
paymentMethod: { activated: true activeLogoSet: null defaultPaymentNote: "" description: "" discountOrFee: {type: 'ABSOLUTE', absoluteValue: {…}, percentageValue: null} lineItemPrice: {amount: 0, currency: 'EUR', taxType: 'GROSS', formatted: '€0.00'} minimumOrderValue: null name: "Cash" officialDescription: "The customer pays the invoice in cash." officialName: "Cash" onlinePayment: false position: 3 selectable: true serviceableCountries: [] workflow: null _id: "79a64f27-8ev6-40ee-b208-9b592ae92097" _links: {self: {…}} }
order:submit
To log this event, you can use the following snippet:
if (window.eComEventTarget) { window.eComEventTarget.addEventListener('order:submit', function(event) { console.log('order:submit', { cart: event.detail.cart, }) }) }
Here’s an example of what you can get:
cart: { billingAddress: null canHaveCoupon: true cartId: "5C06901F-150A-3D9B-B144-D509AB34800" checkoutButtons: [] checkoutState: null checkoutUrl: "/checkout/personal-data" coupon: null couponCampaign: null customerEmail: null grandAmount: "€76.01" grandAmountNote: "components.productComponent.priceExclusiveVat" grandTotal: {amount: 76.01, currency: "EUR", formatted: "€76.01"} minimumOrderValue: null mustAcceptTermsAndConditions: false netAmount: "€76.01" paymentLineItem: {lineItemPrice: {…}, paymentMethod: {…}} pickupToken: "ZjM3M2Q2YmY4jkFjYWRlZTIzZTBlYzQwMDU4MjYzZjYwNDNhZGY0NWM1N2JiNjZhMGI0YWNlNWFkYzU4ZTQ3OF8xNTQzOTM5MjIx" potentialBasketDiscounts: null productLineItems: [{…}, {…}, {…}] registerSessionUrl: "" shippingAddress: null shippingLineItem: {lineItemPrice: {…}, shippingMethod: {…}} status: null subAmount: "€76.01" subAmountValue: 76.01 taxType: "NET" taxes: [] totalBasketDiscount: null totalNumberOfItems: 3 _links: null }
order:completed
Note
|
Please note that your app will only receive this event if the customer accepted all cookies in the cookie notice. |
To log this event, you can use the following snippet:
if (window.eComEventTarget) { window.eComEventTarget.addEventListener('order:completed', function(event) { console.log('order completed') }) }
Here’s an example of what you can get:
order: { pickupLineItem: null billingAddress: null couponCampaign: null currencyId: "EUR" grandTotal: "19.21" lineItemContainer: {productLineItems: Array(0)} orderId: "5D397C93-6BE3-F322-56A6-D5809AB32102" orderNumber: "114264" paymentData: {paymentMethod: {…}} shippingAddress: null shippingData: {price: {…}} totalTax: "3.2" }
App creation
To develop an app using the Beyond API, you need to sign up for a developer test shop.
Note
|
If you want to learn more about how to set up your test shop, visit our Help Center for merchants. |
After you have set up your developer test shop, create a custom app, i.e. an app that only interacts with the Beyond API on behalf of your test shop. In the following, we’ll walk you through the required steps on how to create an app until it is ready for submission.
Generate credentials
Before you can authenticate with a custom app to a Beyond shop, you need to generate the required credentials from the cockpit of the shop you want to connect with your app.
To generate the required credentials:
-
In the sidebar of your test shop’s cockpit, select Apps > Custom apps.
-
Select Add custom app.
-
Enter your app name, and select the scopes that outline the permissions, and access required by your app.
-
Select Save.
You immediately receive your client credentials with a client_id
and a client_secret
.
Store the client_secret
safely, as you will not be able to see it in the Custom apps section again, once you revisit that page.

Authentication & authorization
If you’d like your custom app to interact with the Beyond API, you need to create a JsonWebToken from your client credentials:
-
Send a
POST
request to the token endpoint with thegrant_type
parameter. -
Pass
client_id
andclient_secret
, that you’ve received when generating your credentials in the cockpit, as Basic Auth header.
Our authorization server will respond with a JSON object amongst others containing the access_token
. You can now use it in the Authorization
header with the Bearer
scheme to make authenticated requests to the Beyond API. The token also contains the scopes that authorize you to perform certain actions.
Example:
GET https://api-shop.beyondshop.cloud/api/products HTTP/1.1 Host: yourshop.com Accept: application/hal+json Authorization: Bearer 4HZ9hriF6J3GOnd10JbFzdVehycOvAZf
Happy coding!
Note
|
Please be sure to regularly check our change log to keep track of updates and changes on properties that might affect your app. |
If you’d like to make your app publicly available so that other merchants can use it, your next step would be to implement the authorization flow in your app.
App authorization
To make your app publicly available so that others can use it, an authorization flow within your app is necessary.
How to implement the authorization flow
Your app cannot access merchant data without getting authorization from the merchant first. In this section we will help you through this authorization process.
Prerequisites
In order to make API calls against the Beyond API, you should have been through the steps of creating a custom app. Only then, you can go ahead and implement OAuth 2.0 to request access tokens in order to act on behalf of our merchants.
Authorization process
In the below flow chart, we’ve outlined how we use OAuth 2.0.

You might want to look at some terms that we’ve introduced in the chart.
Name | Description |
---|---|
Merchant |
A shop owner giving permission to an App to access their shop’s data through the REST API. Within the OAuth 2.0 protocol this is referred to as resource owner. |
ePages |
This is where the App can view and modify a shop’s data by accessing the REST API. Within the OAuth 2.0 protocol this is referred to as service provider. |
App |
An application that would like to access a shop’s data. The Merchant must grant permission before the App can access any data. Within the OAuth 2.0 protocol this is referred to as client. |
Now, let’s go through the authorization process together:
1. Obtain user’s consent
Once a merchant has decided to install your application, they have to grant your app the permissions that you’ve selected in the form of scopes during app creation. ePages displays the user consent form to the merchant as follows:

2. Confirm app installation
If the merchant chose to install your application, they will be redirected to the app’s Application Callback URL.
3. Receive authorization code
ePages makes a GET
request to the Application Callback URL provided by the app developer.
The required query parameters that we’ve outlined in the table below will be automatically passed by ePages.
Note
|
SSL required! All API access is over HTTPS. |
Example:
GET/callback?code={code}&signature={signature}&return_url={return_url}&api_url={api_url}&access_token_url={access_token_url} HTTP/1.1 Host: crazytoppingapp.com
Substitutions would be made as given in this example table:
Query parameter | Description | Example |
---|---|---|
{ |
The authorization code that is required for the app installation process to obtain the |
5Q6FBi |
{ |
The base API URL, that uniquely identifies the shop. The |
|
{ |
The URL that the merchant should be redirected to after the app installation. |
|
{ |
The URL to obtain the |
|
{ |
The signature is a message authentification code. It is calculated with the |
jEPRUggebJDBsEnl1%2FpHlMUBxPbsELQihEVzbx2pFlM%3D |
Your app can use the code in combination with your client_id
and client_secret
for obtaining an access_token
.
This code is temporary and will be obsolete after app installation.
Although it is optional to validate the signature
query parameter, we highly recommend to do so, in order to verify that the request was not changed, and for sure has been provided by ePages and no external, malicious party.
In order to understand how to verify the signature, see the following Java code example:
import java.util.Base64; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.CharEncoding; public String calculateSignature(String code, String access_token_url, String client_secret) { String hmacAlgorithm = "HmacSHA1"; final Mac mac = Mac.getInstance(hmacAlgorithm); mac.init(new SecretKeySpec(client_secret.getBytes(CharEncoding.UTF_8), hmacAlgorithm)); byte[] signature = mac.doFinal((code + ":" + access_token_url).getBytes()); return Base64.getEncoder().encodeToString(signature); }
4. Registration (optional)
If your application requires a registration process, this optional step can be included before obtaining the access_token
.
Meanwhile, the app would display the registration or login form to the merchant.
5. Exchange authorization code for access token
To receive an access_token
, make a POST
request to create a JsonWebToken using the authorization_code
grant type:
Request parameters
Parameter | Description |
---|---|
|
OAuth2 grant type. Use |
|
The authorization code. Required for the |
Request header properties
Name | Description |
---|---|
|
The HTTP Basic Authorization header containing the OAuth 2.0 client credentials (client_id:client_secret). |
Example request
$ curl 'https://api-shop.beyondshop.cloud/api/oauth/token' -i -u '553e1b5a-aab9-4264-bd89-a2ee002efe84:tptcc8f8bo0dc4udr334nci4i9' -X POST \
-d 'grant_type=authorization_code&code=mCJjeN'
Response body properties
Path | Type | Description |
---|---|---|
access_token |
String |
The encoded JsonWebToken to access the resource. |
token_type |
String |
Represents how an |
expires_in |
Number |
The time of token expiry in seconds. Calculated from |
scope |
String |
A space-delimited list of scopes the token is issued for. |
tenantId |
Number |
The unique identifier of the tenant. |
iat |
Number |
The timestamp when the token was created (Issued At). Displayed in seconds since the start of the Epoch. Refer to RFC 7519. |
jti |
String |
The token identifier of the token. Is unique for each request. Refer to RFC 7519. |
refresh_token |
String |
The token that can be used to obtain a renewed access token. |
Example response
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Content-Length: 1440
{
"access_token" : "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ.eyJzY29wZSI6WyJ1c2VyOnIiXSwidGVuYW50SWQiOjEzNSwiZXhwIjoxNzQyOTM2MTQ4LCJpYXQiOjE3NDI4OTI5NDgsImp0aSI6IkptNXZLYjA1RXNsc0l1Qk1ST0FpZ0czOHVpUT0iLCJjbGllbnRfaWQiOiI1NTNlMWI1YS1hYWI5LTQyNjQtYmQ4OS1hMmVlMDAyZWZlODQifQ.aTGwMMkOukJot5M0vG2-LivQ_s9BOetnXShieslV_IRxFo2gdzM7f6dmpDT5aFVqPJXChAl1xBtaHcZxjDyrefbsOP-otlxHHpojcqko-HW_sMXiy7ADc0SRe8DlnZSKnmqmbBp0MA0W-Kj3YkCDnmJ7QrU1z-BkPSXvH6rmkDn1xFTi1zlZcrIK-IlFwAYTvm5TVaxMTyYqhjMRwzzJDcRy44fWQNFlFW7Zq1kDX8wgoKYBHQkTTJNAh5KGibvCde6KiOm3wBXcJUmuYu3D58ILGnvf1-6uzw8muXXMm3QUZ3465cQsdh2-eUYD17DYnOHblTisbXqhWn_ak_HSLQ",
"token_type" : "bearer",
"refresh_token" : "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ.eyJzY29wZSI6WyJ1c2VyOnIiXSwiYXRpIjoiSm01dktiMDVFc2xzSXVCTVJPQWlnRzM4dWlRPSIsInRlbmFudElkIjoxMzUsImlhdCI6MTc0Mjg5Mjk0OCwianRpIjoiSlR0My9OM1BJZHBIcWNWc05HY0toV0p0UjZ3PSIsImNsaWVudF9pZCI6IjU1M2UxYjVhLWFhYjktNDI2NC1iZDg5LWEyZWUwMDJlZmU4NCJ9.INK5_NMBULkg4OlOAa89Xbk49uxoy6DlMu9jH038d95U9XuIAQd3VDYzv7GOAhJj8tJoQvmUy2ZrmnpzDVKxSO_0DuxhPRep4MjhJ7vio_diNzZeMQfefoW_Xg7z-BMgMilgKsEGnQhbeFb2w21AeEypy8EOXwyR88i2J05CyIdSIr14PYXCCxxPpEENs4_DEn_secV6hYrIWy2wvHE4VeTTMipDe0R_XFDq1WzJUVQ4N3-qiaYd1pr21KtHkkrpSqHFypYSXOzOd6lsjeTEswjGz-F0o-TmeoYUnh6DCVNr-6Qy32fe5EwY0Ea_xbJn_zI8ETUH3UV9GMhQOhQvAg",
"expires_in" : 43199,
"scope" : "user:r",
"tenantId" : 135,
"iat" : 1742892948,
"jti" : "Jm5vKb05EslsIuBMROAigG38uiQ="
}
Important
|
With this |
What’s more, your access_token
only has a limited lifetime.
The returned expires_in
parameter indicates that.
You need to ensure that you obtain a renewed access_token
when the current token has expired:
Request parameters
Parameter | Description |
---|---|
|
OAuth2 grant type. Use |
|
The token that can be used to obtain a renewed access token when the current token has expired. Required for the |
Request header properties
Name | Description |
---|---|
|
The HTTP Basic Authorization header containing the OAuth 2.0 client credentials (client_id:client_secret). |
Example request
$ curl 'https://api-shop.beyondshop.cloud/api/oauth/token' -i -u 'sample-client:1e52ac81-c1cd-4a53-9dc3-90914500be98' -X POST \
-d 'grant_type=refresh_token&refresh_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ.eyJ1c2VyX25hbWUiOiJ1c2VyIiwic2NvcGUiOlsicHJvZDpyYyJdLCJhdGkiOiJxUjJFbmxMVjlseURTaHVNalFUNnF5cWpCbTA9IiwidGVuYW50SWQiOjE0MzgsImV4cCI6MTc0NTQ4NDkyNSwiaWF0IjoxNzQyODkyOTI1LCJ1c2VySWQiOiIyMTQ4ZGJjNS0wZTIyLTQxMjctYjJmOS1kNDlkN2MwYmQ5ZDUiLCJqdGkiOiJPNW5xcGNXMDVJdzZuVmxtckl2RCtwVVZmREU9IiwiY2xpZW50X2lkIjoic2FtcGxlLWNsaWVudCIsInVzZXJuYW1lIjoidXNlciJ9.K99wtty-GmXB93NI8gGN5SBCK8d7e4oCZZfdbwJgiKCMKBXlxdh056ZpOI-wS3fsZzV4VjTNjSOViVzTA6QClwgEi7omVwNSXYLlLmQ3uCm9bSpXO3yH4iOe2S-m4mWkQEDzlv3Hl5bwrsbkt1bYXR9sAb_CK2xgThV58rzE6tcjcwPjjw0PAlBQu8wtI6qnhY8uUYETpDare-UiczhBk8rOm6qOWpSHf8ip8CMSXHd3goWdGWd2C8J62ldT0nNSCqvQgtRbcBsmTNBJZdM1bAPhtY2Ne5GFFNHsoGI6UGnbBkV2uVXfjIMD5cn8CqqMh6aWcy3ELWJjablWR05N7w'
Response body properties
Path | Type | Description |
---|---|---|
access_token |
String |
The encoded JsonWebToken to access the resource. |
token_type |
String |
Represents how an |
refresh_token |
String |
The token that can be used to obtain a renewed access token. |
expires_in |
Number |
The time of token expiry in seconds. Calculated from |
scope |
String |
A space-delimited list of scopes the token is issued for. |
tenantId |
Number |
The unique identifier of the tenant. |
iat |
Number |
The timestamp when the token was created (Issued At). Displayed in seconds since the start of the Epoch. Refer to RFC 7519. |
userId |
String |
The unique identifier of the user the token was issued for. |
username |
String |
The username that identifies the user the token was issued for. |
jti |
String |
The token identifier of the token. Is unique for each request. Refer to RFC 7519. |
Example response
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Content-Length: 1712
{
"access_token" : "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ.eyJ1c2VyX25hbWUiOiJ1c2VyIiwic2NvcGUiOlsicHJvZDpyYyJdLCJ0ZW5hbnRJZCI6MTQzOCwiZXhwIjoxNzQzMTUyMTI1LCJpYXQiOjE3NDI4OTI5MjUsInVzZXJJZCI6IjIxNDhkYmM1LTBlMjItNDEyNy1iMmY5LWQ0OWQ3YzBiZDlkNSIsImp0aSI6IjEwQWxIVWdOb3NXSW1MS3FyUHZ0TFdYendhdz0iLCJjbGllbnRfaWQiOiJzYW1wbGUtY2xpZW50IiwidXNlcm5hbWUiOiJ1c2VyIn0.TbKAIi_CzBX36omi0xqcumWPek__SGsuRBvo0L-Ji847pDDaDZf957Wo0q9QurM2Vlg4HQxIQZXdvVPdoQfU3Yf34tkuljEqXTqF4lX3FpIF4Q_CgeJ1R1MZ6j4d-b2RxXqdyxhKuI_bUA1L9Dc5AndaleVHItcUO9SKMYHZIoyuUb3bwALar-C_oHIda6KlEAZj_CwQvNKCU_-aBxsHs71kMrRNk6WeOM-uR0ItY7H-W7LqdpwzSHeZmugAkoAqgabb70VzSJ4MkHepYTyfnA3uoRsNZ33o1Ug68iHHHYHM9zxzV3HSQj1__F150P9NJKSZj3B7KibEeuyXDvzn9Q",
"token_type" : "bearer",
"refresh_token" : "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ.eyJ1c2VyX25hbWUiOiJ1c2VyIiwic2NvcGUiOlsicHJvZDpyYyJdLCJhdGkiOiIxMEFsSFVnTm9zV0ltTEtxclB2dExXWHp3YXc9IiwidGVuYW50SWQiOjE0MzgsImV4cCI6MTc0NTQ4NDkyNSwiaWF0IjoxNzQyODkyOTI1LCJ1c2VySWQiOiIyMTQ4ZGJjNS0wZTIyLTQxMjctYjJmOS1kNDlkN2MwYmQ5ZDUiLCJqdGkiOiJPNW5xcGNXMDVJdzZuVmxtckl2RCtwVVZmREU9IiwiY2xpZW50X2lkIjoic2FtcGxlLWNsaWVudCIsInVzZXJuYW1lIjoidXNlciJ9.MiTjBequcth5vuDWRve2Z6pB7TMogOjQHh8xI823eroXzHa4Aq9-BTiZKRXIs3_bKJ4BpahK7BeycavxxLt5opW9g4nLEAbb1k2i6Hx81hO6CSgtCRekAlkWDHEaxhDdV7n9f9Pr2l7vNUQD79CmmEl10pc5bYo4h9mY6amBgC5J94KcM_-9t8sQ_DZO72OyKuJHqlxM-J6cTPp0AZr71NO7mIMrvTX37YsDoBVIKEbU_p5_oQhcZ2RtvTEhKCzPJXD7JYho41dly8THanzhLuOS7Os6wGSYBWziQcrzMFKXtvJ13pzA3DIxiHDGCtPW8jYtf7fD_G-7MkFGKBE2_A",
"expires_in" : 259199,
"scope" : "prod:rc",
"tenantId" : 1438,
"iat" : 1742892925,
"userId" : "2148dbc5-0e22-4127-b2f9-d49d7c0bd9d5",
"username" : "user",
"jti" : "10AlHUgNosWImLKqrPvtLWXzwaw="
}
The refresh_token
from the response has to be stored as well in order to obtain a renewed access_token
.
Here’s an example of how to manage the data of different merchants:
api_url |
Shop | access_token |
expires_in |
refresh_token |
---|---|---|---|---|
API Shop |
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ.eyJzY29wZSI6WyJ1c2VyOnIiXSwidGVuYW50SWQiOjEzNSwiZXhwIjoxNTMwODI1NzIyLCJpYXQiOjE1MzA3ODI1MjIsImp0aSI6IjE5MDE4Mzg0LTNiZTEtNDdhYy1hYTAwLTJjZjNiZWUyYzFlNSIsImNsaWVudF9pZCI6IjJjYjczYzk1LTlmOTEtNDEwNi1iMzdiLWVmN2E2YTBlM2U1ZSJ9.WWgQi7ZGk1ePpvDEhIa7LipkfAN6jwyir1JJrHuxcNVJSIDE63zSBktLCbz_NUAYSommxbMwmWumB5Ah1J51dYNz5UryUagbSMSTI_9pP_WWKMaZ_7E2w4TKjpqSPod8QUUj1RszAGjPseF309st3lrN6xbem6XdGsESIradWrePmcvTovZz8EBoy7GqWZA0Yses_HKfH_Fh3DVOxHavf-iu0m6zm97KBAlWkUXR1HrTG8Q6FFZjPldUg7jBS8wfsmqJTBsGaPfHN5xgLqElBTuGbBBzjG2kae99L8bmPnd00HEG1eIVyokXy30y1GIo3kd4oONcpZGtBhh-r_FdCg |
43199 |
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ.eyJzY29wZSI6WyJ1c2VyOnIiXSwiYXRpIjoiMTkwMTgzODQtM2JlMS00N2FjLWFhMDAtMmNmM2JlZTJjMWU1IiwidGVuYW50SWQiOjEzNSwiaWF0IjoxNTMwNzgyNTIyLCJqdGkiOiI0YzE4YzQ1My00MDg3LTQ3YmEtYTZjZi0xMTBmYTk3NWI0ZjYiLCJjbGllbnRfaWQiOiIyY2I3M2M5NS05ZjkxLTQxMDYtYjM3Yi1lZjdhNmEwZTNlNWUifQ.SZYnVPCZgUDj1kOu_HWVoYapeIvEB4kbgWs6wMkFaIG9ztARajO7vrdHqKu34LH8nI1WSxAEPuQQzSG8y60B8j8l0jp4tMD-3NGvIpkjh0_90_0SlIJF7g—iBCtLoImVODl562jJTV82OOW5MBo31gF6x_qOwCtKx1WQcjK1xwjxK7FdzZ7spzYYj2uD9ocexRrt462VQDA8IIll79RFEyhdkNT44X_bS7wUU0AswVNJxvOrNeEBSza3G7tBJr5z5jMSY0NFHh41cH2Ix-c0AzC0R6FNK_afSlfr65i7RGTzO14OSWy-tYWbvSSlJ5gcjGpvh_slGUJOW4f60qCrg |
|
QuarkyAustrian |
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ.eyJzY29wZSI6WyJ1c2VyOnIiXSwidGVuYW50SWQiOjEzNSwiZXhwIjoxNTMwODI1NzIyLCJpYXQiOjE1MzA3ODI1MjIsImp0aSI6IjE5MDE4Mzg0LTNiZTEtNDdhYy1hYTAwLTJjZjNiZWUyYzFlNSIsImNsaWVudF9pZCI6IjJjYjczYzk1LTlmOTEtNDEwNi1iMzdiLWVmN2E2YTBlM2U1ZSJ9.WWgQi7ZGk1ePpvDEhIa7LipkfAN6jwyir1JJrHuxcNVJSIDE63zSBktLCbz_NUAYSommxbMwmWumB5Ah1J51dYNz5UryUagbSMSTI_9pP_WWKMaZ_7E2w4TKjpqSPod8QUUj1RszAGjPseF309st3lrN6xbem6XdGsESIradWrePmcvTovZz8EBoy7GqWZA0Yses_HKfH_Fh3DVOxHavf-iu0m6zm97KBAlWkUXR1HrTG8Q6FFZjPldUg7jBS8wfsmqJTBsGaPfHN5xgLqElBTuGbBBzjG2kae99L8bmPnd00HEG1eIVyokXy30y1GIo3kd4oONcpZGtBhh-r_FdCg |
259199 |
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ.eyJzY29wZSI6WyJ1c2VyOnIiXSwiYXRpIjoiMTkwMTgzODQtM2JlMS00N2FjLWFhMDAtMmNmM2JlZTJjMWU1IiwidGVuYW50SWQiOjEzNSwiaWF0IjoxNTMwNzgyNTIyLCJqdGkiOiI0YzE4YzQ1My00MDg3LTQ3YmEtYTZjZi0xMTBmYTk3NWI0ZjYiLCJjbGllbnRfaWQiOiIyY2I3M2M5NS05ZjkxLTQxMDYtYjM3Yi1lZjdhNmEwZTNlNWUifQ.SZYnVPCZgUDj1kOu_HWVoYapeIvEB4kbgWs6wMkFaIG9ztARajO7vrdHqKu34LH8nI1WSxAEPuQQzSG8y60B8j8l0jp4tMD-3NGvIpkjh0_90_0SlIJF7g—iBCtLoImVODl562jJTV82OOW5MBo31gF6x_qOwCtKx1WQcjK1xwjxK7FdzZ7spzYYj2uD9ocexRrt462VQDA8IIll79RFEyhdkNT44X_bS7wUU0AswVNJxvOrNeEBSza3G7tBJr5z5jMSY0NFHh41cH2Ix-c0AzC0R6FNK_afSlfr65i7RGTzO14OSWy-tYWbvSSlJ5gcjGpvh_slGUJOW4f60qCrg |
|
TastyFlummery |
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ.eyJzY29wZSI6WyJ1c2VyOnIiXSwidGVuYW50SWQiOjEzNSwiZXhwIjoxNTMwODI1NzIyLCJpYXQiOjE1MzA3ODI1MjIsImp0aSI6IjE5MDE4Mzg0LTNiZTEtNDdhYy1hYTAwLTJjZjNiZWUyYzFlNSIsImNsaWVudF9pZCI6IjJjYjczYzk1LTlmOTEtNDEwNi1iMzdiLWVmN2E2YTBlM2U1ZSJ9.WWgQi7ZGk1ePpvDEhIa7LipkfAN6jwyir1JJrHuxcNVJSIDE63zSBktLCbz_NUAYSommxbMwmWumB5Ah1J51dYNz5UryUagbSMSTI_9pP_WWKMaZ_7E2w4TKjpqSPod8QUUj1RszAGjPseF309st3lrN6xbem6XdGsESIradWrePmcvTovZz8EBoy7GqWZA0Yses_HKfH_Fh3DVOxHavf-iu0m6zm97KBAlWkUXR1HrTG8Q6FFZjPldUg7jBS8wfsmqJTBsGaPfHN5xgLqElBTuGbBBzjG2kae99L8bmPnd00HEG1eIVyokXy30y1GIo3kd4oONcpZGtBhh-r_FdCg |
604800 |
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ.eyJzY29wZSI6WyJ1c2VyOnIiXSwiYXRpIjoiMTkwMTgzODQtM2JlMS00N2FjLWFhMDAtMmNmM2JlZTJjMWU1IiwidGVuYW50SWQiOjEzNSwiaWF0IjoxNTMwNzgyNTIyLCJqdGkiOiI0YzE4YzQ1My00MDg3LTQ3YmEtYTZjZi0xMTBmYTk3NWI0ZjYiLCJjbGllbnRfaWQiOiIyY2I3M2M5NS05ZjkxLTQxMDYtYjM3Yi1lZjdhNmEwZTNlNWUifQ.SZYnVPCZgUDj1kOu_HWVoYapeIvEB4kbgWs6wMkFaIG9ztARajO7vrdHqKu34LH8nI1WSxAEPuQQzSG8y60B8j8l0jp4tMD-3NGvIpkjh0_90_0SlIJF7g—iBCtLoImVODl562jJTV82OOW5MBo31gF6x_qOwCtKx1WQcjK1xwjxK7FdzZ7spzYYj2uD9ocexRrt462VQDA8IIll79RFEyhdkNT44X_bS7wUU0AswVNJxvOrNeEBSza3G7tBJr5z5jMSY0NFHh41cH2Ix-c0AzC0R6FNK_afSlfr65i7RGTzO14OSWy-tYWbvSSlJ5gcjGpvh_slGUJOW4f60qCrg |
6. Redirect the merchant
Once you’re through this process, your app has to send the merchant back to the return_url
the app received before.
In case of a successful app installation, the merchant can now open the app from the cockpit.
If an error occurred during installation, the Install button instead of the Open button will be shown.

Make authenticated API requests
Now that your application has received an access_token
, it can make authenticated requests to the Beyond API, and thus access the shop’s data as long as the app is installed in the shop.
Example request
$ curl 'https://api-shop.beyondshop.cloud/api/product-view/products' -i -X GET \
-H 'Accept: application/hal+json'
Response body properties
Path | Type | Description |
---|---|---|
_embedded.products[]._id |
String |
The unique identifier of the product. |
_embedded.products[].sku |
String |
The stock keeping unit (SKU) corresponding to the product. |
_embedded.products[].name |
String |
The name of the product. |
_embedded.products[].manufacturer |
String |
The manufacturer of the product. |
_embedded.products[].productIdentifiers[] |
Array |
The list of identifiers of the product. |
_embedded.products[].productIdentifiers[].type |
String |
The product code to identify and classify the product. |
_embedded.products[].productIdentifiers[].value |
String |
The actual value of the product identifier. |
_embedded.products[].salesPrice |
Object |
The price of the product. Represents the offer price if a |
_embedded.products[].salesPrice.amount |
Number |
The amount of the sales price. |
_embedded.products[].salesPrice.currency |
String |
The currency of the sales price. |
_embedded.products[].salesPrice.taxModel |
String |
The tax model of the sales price. Can be |
_embedded.products[].type |
String |
The type of the product. Can be one of |
_embedded.products[].minSalesPrice |
Object |
The minimum price of the product. |
_embedded.products[].minSalesPrice.amount |
Number |
The amount of the minimum price of the product. |
_embedded.products[].minSalesPrice.currency |
String |
The currency of the minimum price of the product. |
_embedded.products[].minSalesPrice.taxModel |
String |
The tax model of the minimum price of the product. Can be |
_embedded.products[].maxSalesPrice |
Object |
The maximum price of the product. |
_embedded.products[].maxSalesPrice.amount |
Number |
The amount of the maximum price of the product. |
_embedded.products[].maxSalesPrice.currency |
String |
The currency of the maximum price of the product. |
_embedded.products[].maxSalesPrice.taxModel |
String |
The tax model of the maximum price of the product. Can be |
_embedded.products[].listPrice |
Object |
The previous price of the product that is currently on offer. |
_embedded.products[].listPrice.amount |
Number |
The amount of the list price. |
_embedded.products[].listPrice.currency |
String |
The currency of the list price. |
_embedded.products[].listPrice.taxModel |
String |
The tax model of the list price. Can be |
_embedded.products[].manufacturerPrice |
Object |
The manufacturer’s suggested retail price of the product. |
_embedded.products[].manufacturerPrice.amount |
Number |
The amount of the manufacturer’s suggested retail price. |
_embedded.products[].manufacturerPrice.currency |
String |
The currency of the manufacturer’s suggested retail price. |
_embedded.products[].manufacturerPrice.taxModel |
String |
The tax model of the manufacturer’s suggested retail price. Can be |
_embedded.products[].refPrice |
Object |
The price information scaled to a standardised base unit. |
_embedded.products[].refPrice.refQuantity |
Number |
The reference quantity the product’s reference price is calculated on. |
_embedded.products[].refPrice.unit |
String |
The unit corresponding to the quantity. |
_embedded.products[].refPrice.quantity |
Number |
The actual quantity in the product. |
_embedded.products[].refPrice.price |
Object |
The actual reference price. |
_embedded.products[].refPrice.price.amount |
Number |
The amount of the reference price. |
_embedded.products[].refPrice.price.currency |
String |
The currency of the reference price. |
_embedded.products[].refPrice.price.taxModel |
String |
The tax model of the reference price. Can be |
_embedded.products[].shippingWeight |
Object |
The weight of the product including packaging. |
_embedded.products[].shippingWeight.value |
Number |
The weight value of the product including packaging. |
_embedded.products[].shippingWeight.displayUnit |
String |
The weight unit of the product including packaging. Can be |
_embedded.products[].customText |
Object |
The customization option for a product that allows the customer to add a custom text or a comment. |
_embedded.products[].customText.label |
String |
The headline for the customization text field. |
_embedded.products[].customText.maxLength |
Number |
The maximum length of the custom text the customer can enter for a product. |
_embedded.products[].shippingDimension |
Object |
The shipping dimensions of the product displayed in millimeters (mm). |
_embedded.products[].shippingDimension.length |
Number |
The length of the product including packaging in millimeters (mm). |
_embedded.products[].shippingDimension.width |
Number |
The width of the product including packaging in millimeters (mm). |
_embedded.products[].shippingDimension.height |
Number |
The height of the product including packaging in millimeters (mm). |
_embedded.products[].productLabels[] |
Array |
The labels assigned to the product. |
_embedded.products[].productLabels[].type |
String |
The type of the product label. Can be one of |
_embedded.products[].variationAttributes |
Array |
The variation attributes with its values. |
_embedded.products[].variationAttributes[].displayName |
String |
The name of the variation attribute. |
_embedded.products[].variationAttributes[].values |
Array |
The values of the variation attribute. |
_embedded.products[]._embedded.stockLevel |
Object |
The stock level range of the variations of the variation product. |
_embedded.products[]._embedded.stockLevel.min |
Number |
The lowest stock level across all variations of the variation product. |
_embedded.products[]._embedded.stockLevel.max |
Number |
The highest stock level across all variations of the variation product. |
_embedded.products[]._embedded.stockLevel.stockThreshold |
Number |
The inventory level that indicates that a variation of the variation product needs to be reordered. If the stock level of a variation is equal to or lower than this value but higher than 0, the availability state for the variation is |
_embedded.products[]._embedded.defaultImage |
Object |
The default image of the product. |
_embedded.products[]._embedded.defaultImage.dataUri |
String |
The templated relative download URL of the default product image. |
_embedded.products[]._embedded.defaultImage.width |
Number |
The width of the default product image. |
_embedded.products[]._embedded.defaultImage.height |
Number |
The height of the default product image. |
_embedded.products[]._embedded.availability |
Object |
The information about the availability of the product. |
_embedded.products[]._embedded.availability.stockThreshold |
Number |
The inventory level that indicates that the product needs to be reordered. If the stock level of the product is equal to or lower than this value but higher than 0, the availability state for the product is |
_embedded.products[]._embedded.availability.availableStock |
Number |
The number of products available in stock. |
_embedded.products[]._embedded.availability.availabilityState |
String |
The current availability state for the product. Can be one of |
_embedded.products[]._embedded.availability.purchasable |
Boolean |
Indicates if the product is available for purchase. Can be |
_embedded.products[]._links |
Object |
The links to receive further information related to the product. |
_embedded.products[]._indexedAt |
String |
The time of storing the document in the search index. |
_embedded.products[].additionalDescriptions |
Array |
The list of additional product descriptions of the product and their values. |
_embedded.products[].additionalDescriptions[]._id |
String |
The immutable, unique identifier of the additional product description. |
_embedded.products[].additionalDescriptions[].headline |
String |
The headline of the additional product description. |
_embedded.products[].additionalDescriptions[].htmlDescription |
String |
The text of the additional product description. |
_links |
Object |
See Hypermedia |
page |
Object |
See Pagination |
Example response
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 7189
{"_embedded":{"products":[{"_id":"b148f49b-9f48-4586-9629-b56f4e6cd601","sku":"EB001","name":"High Protein Power Bar (Pack of 5)","manufacturer":"Protein Bar Makers","productIdentifiers":[],"salesPrice":{"amount":4.95,"currency":"EUR","taxModel":"GROSS"},"listPrice":null,"manufacturerPrice":null,"refPrice":null,"shippingWeight":{"value":190.0,"displayUnit":"GRAMS"},"shippingDimension":{"length":19,"width":18,"height":17},"customText":{"label":"Add recipient name","maxLength":20},"_embedded":{"availability":{"stockThreshold":1,"availableStock":5,"availabilityState":"LOW_STOCK","purchasable":true}},"productLabels":[{"type":"SALE"},{"type":"CUSTOMIZABLE"}],"type":"PRODUCT","additionalDescriptions":[{"headline":"About the winery","htmlDescription":"<b>The Grape Vineyard</b><br> <p>\n The Grape Vineyard is one of Spain's most famous wineries,\n especially known for its delicious red wine.\n The vineyard itself dates back to the 18th century and\n has been run by the same family for generations.\n</p>\n","_id":"bf91a0f4-6827-47b6-be2d-348d34e00cb9"},{"headline":"About the vinification","htmlDescription":"<p>\n Creating this delicious wine is a long\n and delicate process with many steps.\n</p> <ol>\n <li>\n The grapes are harvested, carefully selected,\n and prepared for fermentation.\n </li>\n <li>\n After fermentation, the wine is stored in the finest\n oak caskets which give the wine its unique aroma.\n </li>\n <li>\n After going through another careful selection process,\n the wine is finally bottled and ready to be cherished by wine lovers around the globe.\n </li>\n</ol>\n","_id":"a78a47e0-ddca-4185-a84b-71c2050c00ec"}],"_links":{"self":{"href":"https://api-shop.beyondshop.cloud/api/product-view/products/b148f49b-9f48-4586-9629-b56f4e6cd601"},"product":{"href":"https://api-shop.beyondshop.cloud/api/product-view/products/b148f49b-9f48-4586-9629-b56f4e6cd601"},"cross-sells":{"href":"https://api-shop.beyondshop.cloud/api/product-view/products/b148f49b-9f48-4586-9629-b56f4e6cd601/cross-sells"}},"_indexedAt":"2025-04-09T10:52:43"},{"_id":"b2e96ef1-1383-426a-97bc-4cdfdf38c50c","sku":"sh-001","name":"Soft Walk Ultra - Nibok Men's","manufacturer":"Nibok","productIdentifiers":[],"salesPrice":{"amount":89.0,"currency":"EUR","taxModel":"GROSS"},"listPrice":{"amount":99.99,"currency":"EUR","taxModel":"GROSS"},"manufacturerPrice":null,"refPrice":null,"shippingWeight":{"value":190.0,"displayUnit":"GRAMS"},"shippingDimension":{"length":80,"width":80,"height":40},"customText":{"label":"Add recipient name","maxLength":20},"_embedded":{"defaultImage":{"dataUri":"https://api-shop.beyondshop.cloud/api/storage-api/images/nibok-men.jpg?hash=e9a1ce5c0c6abfebec8fb1f6faf77dca7e699999{&width,height,upscale}","width":100,"height":200},"availability":{"stockThreshold":null,"availableStock":null,"availabilityState":"IN_STOCK","purchasable":true}},"productLabels":[{"type":"SALE"},{"type":"CUSTOMIZABLE"}],"type":"PRODUCT","additionalDescriptions":[{"headline":"About the winery","htmlDescription":"<b>The Grape Vineyard</b><br> <p>\n The Grape Vineyard is one of Spain's most famous wineries,\n especially known for its delicious red wine.\n The vineyard itself dates back to the 18th century and\n has been run by the same family for generations.\n</p>\n","_id":"073d22c4-6646-49df-8b86-a9d147677e36"},{"headline":"About the vinification","htmlDescription":"<p>\n Creating this delicious wine is a long\n and delicate process with many steps.\n</p> <ol>\n <li>\n The grapes are harvested, carefully selected,\n and prepared for fermentation.\n </li>\n <li>\n After fermentation, the wine is stored in the finest\n oak caskets which give the wine its unique aroma.\n </li>\n <li>\n After going through another careful selection process,\n the wine is finally bottled and ready to be cherished by wine lovers around the globe.\n </li>\n</ol>\n","_id":"2b1c194c-cec2-4b79-831b-22d36de93879"}],"_links":{"self":{"href":"https://api-shop.beyondshop.cloud/api/product-view/products/b2e96ef1-1383-426a-97bc-4cdfdf38c50c"},"product":{"href":"https://api-shop.beyondshop.cloud/api/product-view/products/b2e96ef1-1383-426a-97bc-4cdfdf38c50c"},"cross-sells":{"href":"https://api-shop.beyondshop.cloud/api/product-view/products/b2e96ef1-1383-426a-97bc-4cdfdf38c50c/cross-sells"}},"_indexedAt":"2025-04-09T10:52:43"},{"_id":"d1bbd85d-c0a4-4d06-a937-40172da82330","name":"Rioja Castillo de Puerto (2013)","manufacturer":"Grape Vineyard","productIdentifiers":[{"type":"EAN","value":"501234567890"},{"type":"UPC","value":"425261"}],"salesPrice":{"amount":8.7,"currency":"EUR","taxModel":"GROSS"},"minSalesPrice":{"amount":8.7,"currency":"EUR","taxModel":"GROSS"},"maxSalesPrice":{"amount":8.7,"currency":"EUR","taxModel":"GROSS"},"listPrice":{"amount":10.95,"currency":"EUR","taxModel":"GROSS"},"manufacturerPrice":{"amount":11.95,"currency":"EUR","taxModel":"GROSS"},"refPrice":{"refQuantity":1,"unit":"LITER","quantity":0.75,"price":{"amount":11.6,"currency":"EUR","taxModel":"GROSS"}},"shippingWeight":{"value":1175.0,"displayUnit":"GRAMS"},"shippingDimension":{"length":1500,"width":1000,"height":2000},"variationAttributes":[{"displayName":"Volume","values":["0.2l","0.7l","1.5l"]}],"customText":{"label":"Add recipient name","maxLength":20},"_embedded":{"defaultImage":{"dataUri":"https://api-shop.beyondshop.cloud/api/storage-api/images/rioja-01.jpg?hash=e9a1ce5c0c6abfebec8fb1f6faf77dca7e6e7777{&width,height,upscale}","width":200,"height":300},"availability":{"stockThreshold":1,"availableStock":5,"availabilityState":"IN_STOCK","purchasable":false},"stockLevel":{"min":0,"max":5,"stockThreshold":1}},"productLabels":[{"type":"SALE"},{"type":"CUSTOMIZABLE"}],"type":"VARIATION_PRODUCT","additionalDescriptions":[{"headline":"About the winery","htmlDescription":"<b>The Grape Vineyard</b><br> <p>\n The Grape Vineyard is one of Spain's most famous wineries,\n especially known for its delicious red wine.\n The vineyard itself dates back to the 18th century and\n has been run by the same family for generations.\n</p>\n","_id":"86c2ceb0-a1a2-4638-8fac-3e82456fbaf7"},{"headline":"About the vinification","htmlDescription":"<p>\n Creating this delicious wine is a long\n and delicate process with many steps.\n</p> <ol>\n <li>\n The grapes are harvested, carefully selected,\n and prepared for fermentation.\n </li>\n <li>\n After fermentation, the wine is stored in the finest\n oak caskets which give the wine its unique aroma.\n </li>\n <li>\n After going through another careful selection process,\n the wine is finally bottled and ready to be cherished by wine lovers around the globe.\n </li>\n</ol>\n","_id":"91f7184d-e21f-4dd3-9a3d-022f7e34091f"}],"_links":{"self":{"href":"https://api-shop.beyondshop.cloud/api/product-view/products/d1bbd85d-c0a4-4d06-a937-40172da82330"},"product":{"href":"https://api-shop.beyondshop.cloud/api/product-view/products/d1bbd85d-c0a4-4d06-a937-40172da82330"},"cross-sells":{"href":"https://api-shop.beyondshop.cloud/api/product-view/products/d1bbd85d-c0a4-4d06-a937-40172da82330/cross-sells"}},"_indexedAt":"2025-04-09T10:52:43"}]},"_links":{"self":{"href":"https://api-shop.beyondshop.cloud/api/product-view/products?page=0&size=40"}},"page":{"size":40,"totalElements":3,"totalPages":1,"number":0}}
Reinstalling an app
It might happen that merchants uninstall and re-install your app.
Optionally, your app can listen to the app.uninstalled
webhook to get informed about such actions.
In all cases, the app installation process should be idempotent and not fail if the app has been installed in the same shop before.
Every time the app is installed, it should exchange the authorization code for a new access and refresh token.
How to run a test authorization
Once you have implemented the authorization flow in your app, you can simulate an installation by a user - in this case yourself. This will trigger the authorization flow.
-
In the sidebar of your test shop’s cockpit, select Apps > Custom apps.
-
Select the app that you’d like to test from the table.
-
Make sure that the Application Callback URL of your app is correct.
-
Select Test authorization.

Selecting Test authorization calls the Application Callback URL
of the app.
Several query parameters are attached to this URL:
Query parameter | Description | Example |
---|---|---|
{ |
The authorization code that is required to obtain the |
5Q6FBi |
{ |
The base API URL, that uniquely identifies the shop. The |
|
{ |
The URL that the merchant should be redirected to after the app installation. |
|
{ |
The URL to obtain the |
|
{ |
The signature is a message authentification code. It is calculated with the |
jEPRUggebJDBsEnl1%2FpHlMUBxPbsELQihEVzbx2pFlM%3D |
Your app can now use the code
in combination with your client_id
and client_secret
for obtaining an access_token
.
To receive this access_token
, make a POST
request to create a JsonWebToken using the authorization_code
grant type:
Request parameters
Parameter | Description |
---|---|
|
OAuth2 grant type. Use |
|
The authorization code. Required for the |
Request header properties
Name | Description |
---|---|
|
The HTTP Basic Authorization header containing the OAuth 2.0 client credentials (client_id:client_secret). |
Example request
$ curl 'https://api-shop.beyondshop.cloud/api/oauth/token' -i -u '553e1b5a-aab9-4264-bd89-a2ee002efe84:tptcc8f8bo0dc4udr334nci4i9' -X POST \
-d 'grant_type=authorization_code&code=mCJjeN'
Response body properties
Path | Type | Description |
---|---|---|
access_token |
String |
The encoded JsonWebToken to access the resource. |
token_type |
String |
Represents how an |
expires_in |
Number |
The time of token expiry in seconds. Calculated from |
scope |
String |
A space-delimited list of scopes the token is issued for. |
tenantId |
Number |
The unique identifier of the tenant. |
iat |
Number |
The timestamp when the token was created (Issued At). Displayed in seconds since the start of the Epoch. Refer to RFC 7519. |
jti |
String |
The token identifier of the token. Is unique for each request. Refer to RFC 7519. |
refresh_token |
String |
The token that can be used to obtain a renewed access token. |
Example response
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Content-Length: 1440
{
"access_token" : "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ.eyJzY29wZSI6WyJ1c2VyOnIiXSwidGVuYW50SWQiOjEzNSwiZXhwIjoxNzQyOTM2MTQ4LCJpYXQiOjE3NDI4OTI5NDgsImp0aSI6IkptNXZLYjA1RXNsc0l1Qk1ST0FpZ0czOHVpUT0iLCJjbGllbnRfaWQiOiI1NTNlMWI1YS1hYWI5LTQyNjQtYmQ4OS1hMmVlMDAyZWZlODQifQ.aTGwMMkOukJot5M0vG2-LivQ_s9BOetnXShieslV_IRxFo2gdzM7f6dmpDT5aFVqPJXChAl1xBtaHcZxjDyrefbsOP-otlxHHpojcqko-HW_sMXiy7ADc0SRe8DlnZSKnmqmbBp0MA0W-Kj3YkCDnmJ7QrU1z-BkPSXvH6rmkDn1xFTi1zlZcrIK-IlFwAYTvm5TVaxMTyYqhjMRwzzJDcRy44fWQNFlFW7Zq1kDX8wgoKYBHQkTTJNAh5KGibvCde6KiOm3wBXcJUmuYu3D58ILGnvf1-6uzw8muXXMm3QUZ3465cQsdh2-eUYD17DYnOHblTisbXqhWn_ak_HSLQ",
"token_type" : "bearer",
"refresh_token" : "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ.eyJzY29wZSI6WyJ1c2VyOnIiXSwiYXRpIjoiSm01dktiMDVFc2xzSXVCTVJPQWlnRzM4dWlRPSIsInRlbmFudElkIjoxMzUsImlhdCI6MTc0Mjg5Mjk0OCwianRpIjoiSlR0My9OM1BJZHBIcWNWc05HY0toV0p0UjZ3PSIsImNsaWVudF9pZCI6IjU1M2UxYjVhLWFhYjktNDI2NC1iZDg5LWEyZWUwMDJlZmU4NCJ9.INK5_NMBULkg4OlOAa89Xbk49uxoy6DlMu9jH038d95U9XuIAQd3VDYzv7GOAhJj8tJoQvmUy2ZrmnpzDVKxSO_0DuxhPRep4MjhJ7vio_diNzZeMQfefoW_Xg7z-BMgMilgKsEGnQhbeFb2w21AeEypy8EOXwyR88i2J05CyIdSIr14PYXCCxxPpEENs4_DEn_secV6hYrIWy2wvHE4VeTTMipDe0R_XFDq1WzJUVQ4N3-qiaYd1pr21KtHkkrpSqHFypYSXOzOd6lsjeTEswjGz-F0o-TmeoYUnh6DCVNr-6Qy32fe5EwY0Ea_xbJn_zI8ETUH3UV9GMhQOhQvAg",
"expires_in" : 43199,
"scope" : "user:r",
"tenantId" : 135,
"iat" : 1742892948,
"jti" : "Jm5vKb05EslsIuBMROAigG38uiQ="
}
Everything worked as expected? Great! The OAuth 2.0 flow of your app is properly implemented.
App submission
There are a few things you need to keep in mind to submit your app. By submitting your app, you take another big step towards letting merchants benefit from your work!
Submission guidelines
Before you start working on it, it’s important that you understand our app submission guidelines. They will help you steer clear of difficulties as you develop your app and provide a structure for you to submit an app that suits our needs. The objective of your app should be meaningful and help our customers achieve their goals: being a successful online merchant.
We’d love to receive your apps!
We want to add great apps to our App Store. In order to allow our merchants to choose from a variety of different apps and meet their requirements, we’d love to see apps from the following categories:
-
Social Commerce
-
Portal Engines
-
Shipping
-
Accounting
-
Content Optimization and Marketing
-
Point of Sale (POS)
-
Sales Analytics
-
Image Service
-
Customer Relationship Management and Newsletters
-
Enterprise Management Systems
Functionality
-
Make sure your app performs as described and advertised. Apps that crash or have obvious bugs will be rejected.
-
Be transparent with your app documentation and features. Apps that include undocumented or hidden features will be rejected.
-
We love to receive the final and production ready version of your app. We will not accept demo, trial or test versions.
-
Save your time and effort and don’t duplicate an app that is already available in the App Store. We may reject it.
-
Concentrate on a reasonable and useful app. Apps that do not function as expected, which trick the user or are in any form misleading will be rejected.
Metadata
-
We are attentive to complete and meaningful descriptions and text in all apps. We will not accept apps that contain placeholder text or incomplete information.
-
Relevance rules. Only provide us with apps that include names, descriptions, screenshots etc. that are relevant to the app content and functionality. Apps that do not comply with this will be rejected.
-
Only submit your app for review with all included URLs fully functional.
-
Make sure that your app respects privacy and does not display personal information of a real person without permission.
Privacy
-
Make sure your app notifies and obtains user consent before collecting, transmitting or using customer or location data. Apps that perform contrary to this will be rejected.
-
We set a high value on security. We will reject apps that transmit viruses as well as files, code or programs that disrupt, damage or spy on our customer’s data.
-
Protect customer data. We will not accept apps that require our customers to share e.g. their email address or date of birth if not necessary for the app’s functionality.
Other
-
Our customers are our greatest asset and we respect them. We will not accept apps that are defamatory, insulting or rude.
-
Apps must comply with all legal requirements in any country where they are made available to our customers. It is in the responsibility of the app developer to understand and conform to the respective local laws and regulations. Please send us an email to apps@epages.com if you have any inquiries.
-
Make sure that all requests are made using OAuth 2.0 authentication.
-
All apps must use an SSL certificate.
-
We will not accept apps that have competitor integrations or references.
Have fun coding!
How to submit your app
Hooray! You have finished coding and made sure to implement an authorization flow to make your app available to others. Exciting!
In the following, we will tell you how to submit your app:
-
In the sidebar of your test shop’s cockpit, navigate to Apps > Custom apps.
-
From the app overview, select the app that you would like to submit.
-
Be sure to provide an Application Callback URL. If you haven’t provided one yet, add the URL and save your changes.
-
Select Submit app.
-
This step is different for new developers (please continue with a) than for developers who have already signed up for an ePages developer account (please continue with b).
-
Select Sign up. Enter your details and select Sign up to confirm your entries and to sign up for an ePages developer account. With your ePages developer account, you can, for example, keep track of the status of all your submitted apps and request changes for app details. Next time you would like to submit a new app, you can simply log in to your account and manage all of your submitted apps in one place.
-
Enter the credentials for your ePages developer account and select Log in.
-
-
Fill out the submission form. The section Walk through the submission form below can help you with that.
-
Select Save in the upper right corner to save your app as draft.
-
Please review all the information that you have entered and be sure to read and understand our submission guidelines. Once your app is ready for review, select Send to review in the upper right corner to request a review of your app by ePages.
-
Confirm your request for review by selecting Ok in the confirmation dialog.
Note
|
As soon as you have sent your app to review, you will not be able to edit the app details anymore until the review is completed. |
Your app is on its way! Yay!
We will send you an email as soon as our review has been completed. Give us a couple of days.
In the meantime, you can always log in to your developer account via https://admin.beyondshop.cloud/sign_in. The tab Submitted apps & changes will provide you with an overview of all of your submitted apps and their current statuses.
Questions? Please contact apps@epages.com.
Walk through the submission form
Before you can submit your app, we’ll ask you to provide us with some information and visuals. This helps us to accept your application for our software. Asterisks ( * ) indicate a required field.
Most of the information you provide will be either displayed to merchants in the app list view or in the app detail view.
The app list view displays several apps next to each other. Here’s an example:

The app detail page provides further information on your app once it’s selected from the app list view. Here’s an example:

App type
Select the type of your app. In which context does your app support the merchant?
Application Callback URL
The Application Callback URL serves as the target URL after the merchant has confirmed the installation of your app.
The URL query parameters required for the OAuth 2.0 authorization code flow (e.g. code
, access_token_url
, signature
, and return_url
) are appended automatically by ePages.
Make sure that this URL is SSL and public.
Note
|
In order to allow Single sign-on (SSO) for the users of your app, the Application Callback URL will also be called to authenticate the request and direct the user to the desired page of your app and thus log them in automatically. If SSO is not desired for your app, please provide an App URL different from the Application Callback URL further below. |
Languages
Determine in which languages your app is available. Your app can only be activated for a shop if you have provided the app details in the respective shop language. From the Language dropdown, select the language you would like to provide the app details for. If you decide to offer your app in multiple languages, select Add language. You will then also have to fill out all mandatory fields for the additional language(s).
Tip
|
If you are adding a language that is similar to a language for which you have already provided the app details, you can take over the respective texts from that language to reduce your effort. To do so, select the language that includes the app details you would like to take over to your current language from the dropdown next to Use texts from selected language. Then select Use texts from selected language and review the entries. |
App name
The name of your app as it should be shown to merchants.
Description
Write a short description of your app with max. 1024 characters. Provide information about its advantages and features.
Example:
Handle your shipping process with ease:
Automatic order synchronisation and ready-to-print shipping labels.
App URL
Optional: The target URL when selecting your app after a successful installation.
Note
|
In order to allow Single sign-on (SSO) for the users of your app, we recommend to not provide a specific App URL. Instead, the Application Callback URL should also serve as the target URL when selecting your app after a successful installation. If that behavior is not supported by your app or differs from your desired workflow, you can still provide a different App URL. |
Price
Enter the price of your app or other requirements for using your service.
Example: Free trial period. Subscription model: $19.99 per month.
Developer or company name
Provide the name of the individual(s) or the company that is responsible for the app’s development.
Developer or company website
Provide the website of the individual(s) or the company that is responsible for the app’s development.
Customer support email address
Provide an email address for merchant support.
Customer support website
Provide a website for merchant support.
Video URL
Optional: Provide the URL of a video presenting or explaining your app.
Example:
YouTube
https://www.youtube.com/watch?v={Id}
Logo shown in app list
Recommended size: 320x200 px; Supported formats: PNG, JPEG, and GIF.
Logo shown on app detail page
Recommended size: 140x140 px; Supported formats: PNG, JPEG, and GIF.
App screenshots
Recommended size: 780x465 px; Supported formats: PNG, JPEG, and GIF.
Before submitting your app, please review all the information that you have entered and be sure to read and understand our submission guidelines.