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.

standard app

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.

system app

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

catg:c

Create product category

catg:r

List product categories, Show product category details, Search product categories, Find manual categories, Find used category tags, Find category manufacturers

catg:u

Update all product category properties, Update product category partially (json), Add multiple products to product categories, Remove multiple products from product categories

catg:d

Delete product category

ccgn:c

Create coupon campaign, Update coupon codes

ccgn:r

List coupon campaigns, Show coupon campaign details, List coupon codes

ccgn:u

Update coupon campaign, Update coupon campaign status

ccgn:d

Delete coupon campaign

clpr:c

Create cancelation process, Cancel order

clpr:r

List cancelation processes, Show cancelation process details

csac:r

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

csac:u

Update shipping address in customer account, Update billing address in customer account

csac:d

Delete customer account

cset:r

List checkout settings

cset:u

Update checkout settings

cust:c

Create customer

cust:r

List customers, Show customer details, List customer events

cust:u

Update customer

cust:d

Delete customer

lang:r

Show language details, List languages, List supported languages

lcnt:u

Update legal content

legl:r

Show legal details

legl:u

Update legal resource partially (json)

loca:c

Create location

loca:r

List locations, Show location details

loca:u

Update location

loca:d

Delete location

nltg:m

Create newsletter target, Update newsletter target, Delete newsletter target

orde:r

List order events

ordr:c

Create order

ordr:r

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

ordr:u

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

ordp:r

List order processes

oset:r

List order settings

oset:u

Update order settings

paym:m

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

pccd:c

Create category customer group discount

pccd:r

List category customer group discounts by category, List category customer group discounts by customer group, Show category customer group discount details

pccd:u

Update category customer group discount

pccd:d

Delete category customer group discount

pcgd:c

Create product customer group discount

pcgd:r

List product customer group discounts by product, List product customer group discounts by customer group, Show product customer group discount details

pcgd:u

Update product customer group discount

pcgd:d

Delete product customer group discount

prad:c

Create product attribute definition

prad:r

List product attribute definitions, Show product attribute definition details

prad:d

Delete product attribute definition

prat:c

Create product attribute

prat:d

Delete product attribute

prat:r

Show product attribute details, List product attributes

prat:u

Update product attribute

prcs:c

Create product cross-sell

prcs:r

List product cross-sells, Show product cross-sell details

prcs:u

Update product cross-sell

prcs:d

Delete product cross-sell

prda:r

Show product availability details, Show variation availability details

prda:u

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

prod:c

Create product, Create variation product

prod:r

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

prod:u

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

prod:d

Delete product, Delete multiple products

pymt:r

List payment methods, Show payment method details, Generate referral URI, Show merchant account details

pymt:u

Update payment method, Sort payment methods, Activate payment method, Deactivate payment method

pypr:r

List payment processes, Show payment process details, Show active payment process details, Show online payment process details

pypr:u

Mark payment process as voided, Mark payment process as paid, Capture payment

rfpr:r

List refund processes, Show refund process details, Show active refund process details

rfpr:u

Mark refund process as paid

rtpr:c

Create return process

rtpr:r

List return processes, Show return process details

sctg:m

Create script tag, Update script tag, Delete script tag

shad:u

Update address partially (json)

shat:c

Create shop attribute

shat:r

List shop attributes, Show shop attribute details

shat:u

Update shop attribute

shat:d

Delete shop attribute

shim:c

Create shop image, Upload shop image

shim:r

List shop images, Show shop image details, Find shop images by label

shim:d

Delete shop image

shop:u

Update shop partially (json)

shpr:c

Create shipping process, Create pickup process

shpr:r

List shipping processes, Show shipping process details, List pickup processes, Show pickup process details

shpr:u

Mark shipment as shipped, Mark shipment as delivered, Mark pickup process as picked up

shpz:c

Create shipping zone, Create pickup option

shpz:r

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

shpz:u

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

shpz:d

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

page:view

Is triggered when the customer opens or reloads a page. Informs about the path of the page.

product:view

Is triggered when the customer accesses a product detail page. Informs about the respective product as well as the current state of the cart.

product:click

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.

category:view

Is triggered when the customer selects a page displaying a product category. Informs about the respective category and included products.

searchResults:view

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.

cart:view

Is triggered when the customer accesses the cart. Informs about the current state of the cart, for example, about included items.

cart:add

Is triggered when the customer adds a product to the cart. Provides information about the current state of the cart and the added product.

cart:setQuantity

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.

cart:update

Is triggered when the cart is changed on the cart overview. Informs about the current state of the cart, for example, about included items.

customer:signUp

Is triggered when a customer successfully signs up for a customer account. Informs about the customer’s email address and name.

customer:signIn

Is triggered when a customer successfully signs in to their customer account. Informs about the customer’s email address.

shippingMethod:select

Is triggered when a customer selects a shipping method or pickup option during checkout. Informs about the selected shipping method or pickup option.

paymentMethod:select

Is triggered when a customer selects a payment method during checkout. Informs about the selected payment method.

order:submit

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.

order:completed

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:

  1. In the sidebar of your test shop’s cockpit, select Apps > Custom apps.

  2. Select Add custom app.

  3. Enter your app name, and select the scopes that outline the permissions, and access required by your app. private apps first step

  4. 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.

private apps client credentials new

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:

  1. Send a POST request to the token endpoint with the grant_type parameter.

  2. Pass client_id and client_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.

oauth2 flow

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:

install app

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

{code}

The authorization code that is required for the app installation process to obtain the access_token.

5Q6FBi

{api_url}

The base API URL, that uniquely identifies the shop. The api_url differs for every shop and has to be stored in the app.

https://api-shop.beyondshop.cloud/api

{return_url}

The URL that the merchant should be redirected to after the app installation.

https://api-shop.beyondshop.cloud/cockpit

{access_token_url}

The URL to obtain the access_token.

https://api-shop.beyondshop.cloud/api/oauth/token

{signature}

The signature is a message authentification code. It is calculated with the code, access_token_url, and client_secret.

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

grant_type

OAuth2 grant type. Use client_credentials for client credentials flow, authorization_code for authorization code flow, and refresh_token to refresh an access token.

code

The authorization code. Required for the authorization_code grant type.

Request header properties

Name Description

Authorization

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 accessToken will be generated and presented for accessing a resource. Always issued as Bearer.

expires_in

Number

The time of token expiry in seconds. Calculated from iat.

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 access_token you make authenticated requests to the shop’s data as long as the app is installed in the merchant’s shop. Store the access_token securely. It is only valid for the current shop, i.e. you should also store the api_url along with the access_token.

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

grant_type

OAuth2 grant type. Use client_credentials for client credentials flow, authorization_code for authorization code flow, and refresh_token to refresh an access token.

refresh_token

The token that can be used to obtain a renewed access token when the current token has expired. Required for the refresh_token grant type.

Request header properties

Name Description

Authorization

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 accessToken will be generated and presented for accessing a resource. Always issued as Bearer.

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 iat.

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

https://api-shop.beyondshop.cloud

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

https://quarkyaustrian.beyondshop.cloud

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

https://tastyflummery.beyondshop.cloud

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.

open app

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 listPrice is set. Otherwise, it represents the regular price of the product.

_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 GROSS or NET.

_embedded.products[].type

String

The type of the product. Can be one of PRODUCT, VARIATION_PRODUCT, or VARIATION.

_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 GROSS or NET.

_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 GROSS or NET.

_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 GROSS or NET.

_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 GROSS or NET.

_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 GROSS or NET.

_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 GRAMS or KILOGRAMS. Defaults to GRAMS.

_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 SALE, NEW, or CUSTOMIZABLE.

_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 LOW_STOCK.

_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 LOW_STOCK.

_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 IN_STOCK, LOW_STOCK, OUT_OF_STOCK, or NOT_AVAILABLE.

_embedded.products[]._embedded.availability.purchasable

Boolean

Indicates if the product is available for purchase. Can be true or false. If the product is not available for purchase, its availability state is NOT_AVAILABLE.

_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.

  1. In the sidebar of your test shop’s cockpit, select Apps > Custom apps.

  2. Select the app that you’d like to test from the table.

  3. Make sure that the Application Callback URL of your app is correct.

  4. Select Test authorization.

test authorization button

Selecting Test authorization calls the Application Callback URL of the app. Several query parameters are attached to this URL:

Query parameter Description Example

{code}

The authorization code that is required to obtain the access_token.

5Q6FBi

{api_url}

The base API URL, that uniquely identifies the shop. The api_url differs for every shop and has to be stored in the app.

https://api-shop.beyondshop.cloud/api

{return_url}

The URL that the merchant should be redirected to after the app installation.

https://api-shop.beyondshop.cloud/cockpit

{access_token_url}

The URL to obtain the access_token.

https://api-shop.beyondshop.cloud/api/oauth/token

{signature}

The signature is a message authentification code. It is calculated with the code, access_token_url, and client_secret.

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

grant_type

OAuth2 grant type. Use client_credentials for client credentials flow, authorization_code for authorization code flow, and refresh_token to refresh an access token.

code

The authorization code. Required for the authorization_code grant type.

Request header properties

Name Description

Authorization

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 accessToken will be generated and presented for accessing a resource. Always issued as Bearer.

expires_in

Number

The time of token expiry in seconds. Calculated from iat.

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:

  1. In the sidebar of your test shop’s cockpit, navigate to Apps > Custom apps.

  2. From the app overview, select the app that you would like to submit.

  3. Be sure to provide an Application Callback URL. If you haven’t provided one yet, add the URL and save your changes.

  4. Select Submit app.

  5. 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).

    1. 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.

    2. Enter the credentials for your ePages developer account and select Log in.

  6. Fill out the submission form. The section Walk through the submission form below can help you with that.

  7. Select Save in the upper right corner to save your app as draft.

  8. 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.

  9. 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:

app list view two examples

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

app detail page esitekic

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.